Neutral freight reference + validation layer for AI agents: ADR, HS, UN/LOCODE, freight math
io.github.SoapyRED/freightutils MCP Server
The io.github.SoapyRED/freightutils Model Context Protocol (MCP) server provides a neutral freight reference and validation layer for AI agents. Its description highlights support for ADR, HS, UN/LOCODE, and freight math, intended to support freight-related lookups and validation.
๐ ๏ธ Key Features
Neutral freight reference
Validation layer for AI agents
ADR support
HS support
UN/LOCODE support
Freight math
๐ Use Cases
Freight data validation in AI agent workflows
Reference lookups for logistics inputs (ADR, HS, UN/LOCODE)
Calculations related to freight math
โก Developer Benefits
MCP integration with 25 tools (toolCount: 25)
Topics include ai-agents, freight, logistics, mcp, model-context-protocol
โ ๏ธ Limitations
The available source data does not list individual tool names, request/response formats, or configuration options.
Calculate cubic metres (CBM) for a shipment from per-piece dimensions. CBM is the standard volume unit in international shipping: 1 CBM = 1m x 1m x 1m = 1,000 litres, and ocean freight prices per "freight tonne" (1 CBM or 1,000 kg, whichever is greater).
Behavior: deterministic โ identical inputs always return identical figures; total volume = pieces x per-piece CBM, with conversions to cubic feet, cubic inches and litres included. Missing or non-positive dimensions error with a validation message naming the parameter. Rate-limited (anonymous use: 25 requests/day per IP): a 429 error body carries retry_after_seconds and a Retry-After header โ back off and retry, or call get_subscribe_link for higher limits.
Returns: cbm_per_piece, total_cbm, cubic_feet, litres, cubic_inches and pieces under result, plus confidence, _source and citation (the FreightUtils v1 response envelope).
Related: chargeable_weight_calculator (air billing weight from the same dims), consignment_calculator (multi-line totals), unit_converter (single conversions), shipment_summary (full composite analysis).
Calculate air freight chargeable weight โ the greater of actual gross weight and volumetric weight, which is what airlines bill. Volumetric weight (kg) = (L x W x H in cm) / divisor; the IATA-standard divisor is 6,000 (1 CBM = 166.67 kg), while express integrators (DHL, FedEx, UPS) typically use 5,000.
Behavior: deterministic; per-piece volumetric weight is rounded to 2 decimal places before totalling; basis reports which weight governs ("volumetric" = cargo is light for its size, "actual" = dense). Air mode only โ sea W/M (1 CBM = 1,000 kg) is covered by consignment_calculator with mode=sea. Missing or non-positive inputs error with the failing parameter named. Rate-limited (anonymous use: 25 requests/day per IP): a 429 error body carries retry_after_seconds and a Retry-After header โ back off and retry, or call get_subscribe_link for higher limits.
Returns: chargeable_weight_kg, basis, volumetric_weight_kg (total and per piece), gross_weight_kg, cbm, ratio, factor and pieces under result; normalized_input echoes the interpreted inputs and any defaults applied; plus confidence, _source and citation (the FreightUtils v1 response envelope).
Related: cbm_calculator (volume only), consignment_calculator (multi-line, all modes), uld_lookup (the equipment the freight flies in).
Calculate loading metres (LDM) for European road freight โ how much trailer length a pallet load occupies. 1 LDM = 1 linear metre of a 2.4m-wide trailer; a standard artic is 13.6 LDM.
Provide a pallet preset OR custom length_mm + width_mm โ omitting both errors with a usage hint. Behavior: deterministic; stackable=true with stack_height 2 or 3 divides the floor footprint accordingly; fits reports whether the load fits the chosen vehicle's LENGTH (give weight_kg to also see total_weight_kg against the vehicle's max payload); utilisation_percent is of the vehicle's length. Rate-limited (anonymous use: 25 requests/day per IP): a 429 error body carries retry_after_seconds and a Retry-After header โ back off and retry, or call get_subscribe_link for higher limits.
Returns: ldm, vehicle (name, length_m, max_payload_kg), utilisation_percent, pallet_spaces (used/available), total_weight_kg, fits and warnings under result, plus confidence, _source and citation (the FreightUtils v1 response envelope).
Related: vehicle_lookup (the trailer specs behind the vehicle presets), pallet_fitting_calculator (boxes onto one pallet), consignment_calculator (mixed lines including LDM).
Parameters9
pallet
string
optional
Pallet preset
length_mm
number
optional
Custom pallet length in mm
width_mm
number
optional
Custom pallet width in mm
quantity
integer
optional
Number of pallets (default: 1)
stackable
boolean
optional
Can pallets be stacked?
stack_height
integer
optional
Stack height 2 or 3
weight_kg
number
optional
Weight per pallet in kg
vehicle
string
optional
Vehicle type. DEPRECATED: rigid10 (removal in 3.0.0) โ its 10 m length is published by no manufacturer; use custom with vehicle_length_m, or artic.
vehicle_length_m
number
optional
Custom vehicle length in m
Raw schema
{
"type": "object",
"properties": {
"pallet": {
"description": "Pallet preset",
"type": "string",
"enum": [
"euro",
"uk",
"half",
"quarter"
]
},
"length_mm": {
"description": "Custom pallet length in mm",
"type": "number",
"exclusiveMinimum": 0
},
"width_mm": {
"description": "Custom pallet width in mm",
"type": "number",
"exclusiveMinimum": 0
},
"quantity": {
"description": "Number of pallets (default: 1)",
"type": "integer",
"exclusiveMinimum": 0,
"maximum": 9007199254740991
},
"stackable": {
"description": "Can pallets be stacked?",
"type": "boolean"
},
"stack_height": {
"description": "Stack height 2 or 3",
"type": "integer",
"minimum": 2,
"maximum": 3
},
"weight_kg": {
"description": "Weight per pallet in kg",
"type": "number",
"exclusiveMinimum": 0
},
"vehicle": {
"description": "Vehicle type. DEPRECATED: rigid10 (removal in 3.0.0) โ its 10 m length is published by no manufacturer; use custom with vehicle_length_m, or artic.",
"type": "string",
"enum": [
"artic",
"rigid10",
"rigid75",
"luton",
"us53",
"us48",
"custom"
]
},
"vehicle_length_m": {
"description": "Custom vehicle length in m",
"type": "number",
"exclusiveMinimum": 0
}
},
"$schema": "http://json-schema.org/draft-07/schema#"
}
adr_lookup
Look up European road dangerous-goods (ADR 2025) reference data for a substance: hazard class, classification code, packing group, labels, special provisions, limited/excepted quantities, transport category, tunnel restriction code and Kemler (hazard identification) number. Covers 2,939 entries across all 9 hazard classes, from UNECE ADR 2025 (ECE/TRANS/352).
Provide exactly ONE of: un_number (exact lookup โ returns every packing-group variant of that UN number), search (case-insensitive partial match on the proper shipping name), or hazard_class (all entries in a class or division). un_number is normalised โ "1203", "UN1203" and "un 1203" are equivalent, and normalized_input reports the correction; explosives keep their leading zero ("0004").
Behavior: read-only reference lookup; name searches return up to 50 entries, class filters up to 100. An unknown UN number or a search with no hits errors with the API's NOT_FOUND body and a retry hint. 28 Table A rows carry a scope remark instead of a packing group: those return packing_group null plus not_subject_to_adr (with conditions_ref, e.g. "5.5.3" for UN 1845 dry ice) or carriage_prohibited, and table_a_remark preserves the verbatim Table A text. Rate-limited (anonymous use: 25 requests/day per IP): a 429 error body carries retry_after_seconds and a Retry-After header โ back off and retry, or call get_subscribe_link for higher limits.
Returns: count and results[] โ per entry: un_number, proper_shipping_name, class, classification_code, packing_group, labels, special_provisions, limited_quantity, excepted_quantity, transport_category, tunnel_restriction_code, hazard_identification_number, variant_index/variant_count and, on scope-flagged rows, not_subject_to_adr/carriage_prohibited/conditions_ref/table_a_remark โ under result, plus confidence, _source and citation (the FreightUtils v1 response envelope).
Limitations: a factual compilation of the ADR table, not legal or compliance advice; classification remains the consignor's responsibility โ verify against the current UNECE ADR text.
Related: adr_lq_eq_check (checks quantities against the LQ/EQ values returned here), adr_exemption_calculator (1.1.3.6 small-load points), consignment_calculator (flags dangerous-goods lines by UN number).
Parameters3
un_number
string
optional
Exact UN number โ 4 digits, optionally "UN"-prefixed; explosives keep their leading zero. Examples: "1203", "UN1203", "0004".
search
string
optional
Case-insensitive partial match on the proper shipping name (min 2 characters). Example: "acetone".
hazard_class
string
optional
Filter by ADR hazard class and its divisions. Examples: "3" (flammable liquids), "6.1" (toxic), "8" (corrosive), "1.4" (an explosives division).
Raw schema
{
"type": "object",
"properties": {
"un_number": {
"description": "Exact UN number โ 4 digits, optionally \"UN\"-prefixed; explosives keep their leading zero. Examples: \"1203\", \"UN1203\", \"0004\".",
"type": "string",
"pattern": "^(UN)?\\d{4}$"
},
"search": {
"description": "Case-insensitive partial match on the proper shipping name (min 2 characters). Example: \"acetone\".",
"type": "string",
"minLength": 2
},
"hazard_class": {
"description": "Filter by ADR hazard class and its divisions. Examples: \"3\" (flammable liquids), \"6.1\" (toxic), \"8\" (corrosive), \"1.4\" (an explosives division).",
"type": "string"
}
},
"$schema": "http://json-schema.org/draft-07/schema#"
}
adr_exemption_calculator
Calculate ADR 1.1.3.6 "small load" exemption points for a dangerous-goods load. Each substance's transport category (0-4) sets a points multiplier (category 1 x50, 2 x3, 3 x1, 4 x0; the nine ADR 1.1.3.6.3 note-a entries UN 0081/0082/0084/0241/0331/0332/0482/1005/1017 are x20 with a 50 kg per-transport-unit cap); points = quantity x multiplier, and a load totalling 1,000 points or less qualifies for reduced ADR requirements. Transport category 0 substances can NEVER use this exemption โ has_category_zero flags them.
Provide un_number + quantity for a single substance, or items[] for a mixed load (items takes precedence if both are given). Quantities are in kg or litres per the substance's ADR unit.
Multi-variant UNs: a UN number with more than one ADR Table A row (packing group / concentration variant โ e.g. UN 1789 PG II vs PG III have different transport categories) needs packing_group (I|II|III) or variant_index (from adr_lookup) to pin one row. Without a disambiguator the tool returns blocking_errors[AMBIGUOUS_UN_VARIANT] + human_review_required + candidates[] (each candidate's variant_index, packing_group, proper_shipping_name, transport_category, multiplier) and NO verdict, rather than silently guessing a row. Single-row UNs are unchanged.
Scope verdicts: Table A rows listed "NOT SUBJECT TO ADR" or "CARRIAGE PROHIBITED" never enter the points math. An all-not-subject load (e.g. UN 1845 dry ice) returns not_subject_to_adr true with a dedicated message ("Not subject to ADR (road). Section 5.5.3 applies: ...") and, for dry ice, conditions[] quoting the ADR 2025 section 5.5.3 requirements verbatim (ventilation, package marking, warning mark, documentation, training). A load containing a CARRIAGE PROHIBITED entry returns exempt false with carriage_prohibited true. In a mixed load, not-subject items are excluded from the points and the exclusion is stated in warnings.
Behavior: deterministic points arithmetic over ADR 2025 reference data; a UN that cannot be found returns blocking_errors (NOT_FOUND); exempt is the overall verdict. Rate-limited (anonymous use: 25 requests/day per IP): a 429 error body carries retry_after_seconds and a Retry-After header โ back off and retry, or call get_subscribe_link for higher limits.
Returns: items[] (each with packing_group, variant_index, transport_category, multiplier, points, quantity_unit/quantity_basis/expected_unit when a unit or basis was declared, and scope flags where applicable), total_points (NULL when no verdict was reached), threshold (1000), exempt (NULL when no verdict was reached โ never false as a stand-in), has_category_zero, has_quantity_exceedance, warnings, message and โ on scope verdicts โ not_subject_to_adr/conditions_ref/conditions[]/carriage_prohibited under result โ or, when a UN is ambiguous, human_review_required + candidates[] with blocking_errors, plus confidence, _source and citation (the FreightUtils v1 response envelope).
Limitations: a deterministic calculation over reference data, not legal advice โ even exempt loads keep core duties (packaging, marking, documentation), and mixed-packing rules still apply; verify against the current UNECE ADR text.
Related: adr_lookup (per-substance data incl. transport category + variant_index), adr_lq_eq_check (the LQ/EQ relief routes instead of 1.1.3.6).
Parameters7
un_number
string
optional
UN number for single check (4 digits, optionally "UN"-prefixed)
quantity
number
optional
Quantity on the ADR 1.1.3.6.3 basis: net kg for solids and liquefied, refrigerated or dissolved gases; litres for liquids; receptacle water capacity in litres for compressed or adsorbed gases and chemicals under pressure; articles as the mass of the articles without their packagings, in kg.
packing_group
string
optional
Packing group (I, II or III) โ only needed to disambiguate a UN that has more than one ADR Table A row (e.g. UN 1789). Ignored for single-row UNs.
variant_index
integer
optional
ADR Table A variant index (as returned by adr_lookup) โ pins one row when a UN has several variants that share a packing group (e.g. concentration bands). Ignored for single-row UNs.
unit
string
optional
OPTIONAL. The dimension `quantity` is stated in โ 'L' or 'kg'. Omit it and the number is taken as already on the ADR 1.1.3.6.3 basis (the historical contract). Supply it and it is CHECKED against the dimension 1.1.3.6.3 counts for the row: litres for liquids and for compressed or adsorbed gases, kilograms for solids, liquefied/refrigerated/dissolved gases and articles. A mismatch returns no points and says which dimension the entry is counted in.
basis
string
optional
OPTIONAL. 'net' or 'gross'. ADR 1.1.3.6.3 counts the dangerous goods themselves, never the packaging, so a figure declared 'gross' returns no points in ANY unit โ send the net quantity instead.
items
array
optional
Array of items for mixed-load check
Raw schema
{
"type": "object",
"properties": {
"un_number": {
"description": "UN number for single check (4 digits, optionally \"UN\"-prefixed)",
"type": "string",
"pattern": "^(UN)?\\d{4}$"
},
"quantity": {
"description": "Quantity on the ADR 1.1.3.6.3 basis: net kg for solids and liquefied, refrigerated or dissolved gases; litres for liquids; receptacle water capacity in litres for compressed or adsorbed gases and chemicals under pressure; articles as the mass of the articles without their packagings, in kg.",
"type": "number",
"exclusiveMinimum": 0
},
"packing_group": {
"description": "Packing group (I, II or III) โ only needed to disambiguate a UN that has more than one ADR Table A row (e.g. UN 1789). Ignored for single-row UNs.",
"type": "string",
"enum": [
"I",
"II",
"III"
]
},
"variant_index": {
"description": "ADR Table A variant index (as returned by adr_lookup) โ pins one row when a UN has several variants that share a packing group (e.g. concentration bands). Ignored for single-row UNs.",
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
},
"unit": {
"description": "OPTIONAL. The dimension `quantity` is stated in โ 'L' or 'kg'. Omit it and the number is taken as already on the ADR 1.1.3.6.3 basis (the historical contract). Supply it and it is CHECKED against the dimension 1.1.3.6.3 counts for the row: litres for liquids and for compressed or adsorbed gases, kilograms for solids, liquefied/refrigerated/dissolved gases and articles. A mismatch returns no points and says which dimension the entry is counted in.",
"type": "string",
"enum": [
"L",
"kg"
]
},
"basis": {
"description": "OPTIONAL. 'net' or 'gross'. ADR 1.1.3.6.3 counts the dangerous goods themselves, never the packaging, so a figure declared 'gross' returns no points in ANY unit โ send the net quantity instead.",
"type": "string",
"enum": [
"net",
"gross"
]
},
"items": {
"description": "Array of items for mixed-load check",
"type": "array",
"items": {
"type": "object",
"properties": {
"un_number": {
"type": "string",
"pattern": "^(UN)?\\d{4}$",
"description": "UN number (4 digits, optionally \"UN\"-prefixed)"
},
"quantity": {
"type": "number",
"exclusiveMinimum": 0,
"description": "Quantity on the ADR 1.1.3.6.3 basis: net kg for solids and liquefied, refrigerated or dissolved gases; litres for liquids; receptacle water capacity in litres for compressed or adsorbed gases and chemicals under pressure; articles as the mass of the articles without their packagings, in kg."
},
"packing_group": {
"description": "Packing group for a multi-variant UN.",
"type": "string",
"enum": [
"I",
"II",
"III"
]
},
"variant_index": {
"description": "ADR Table A variant index for a multi-variant UN.",
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
},
"unit": {
"description": "OPTIONAL. The dimension `quantity` is stated in โ 'L' or 'kg'. Omit it and the number is taken as already on the ADR 1.1.3.6.3 basis (the historical contract). Supply it and it is CHECKED against the dimension 1.1.3.6.3 counts for the row: litres for liquids and for compressed or adsorbed gases, kilograms for solids, liquefied/refrigerated/dissolved gases and articles. A mismatch returns no points and says which dimension the entry is counted in.",
"type": "string",
"enum": [
"L",
"kg"
]
},
"basis": {
"description": "OPTIONAL. 'net' or 'gross'. ADR 1.1.3.6.3 counts the dangerous goods themselves, never the packaging, so a figure declared 'gross' returns no points in ANY unit โ send the net quantity instead.",
"type": "string",
"enum": [
"net",
"gross"
]
}
},
"required": [
"un_number",
"quantity"
]
}
}
},
"$schema": "http://json-schema.org/draft-07/schema#"
}
airline_lookup
Search 6,357 airlines by name, IATA code, ICAO code, AWB prefix, or country. AWB prefixes are the first 3 digits of an air waybill number and identify the issuing carrier (e.g. 176 = Emirates).
Provide ONE parameter: query is a ranked fuzzy search across names and codes; iata / icao / prefix / country are exact filters.
Behavior: read-only; fuzzy query hits report their match quality through the envelope's confidence (basis match_quality, score 0-1) with a FUZZY_BEST_MATCH advisory naming the matched field; a query with no hits returns count 0 with a NO_MATCH advisory rather than an error. Rate-limited (anonymous use: 25 requests/day per IP): a 429 error body carries retry_after_seconds and a Retry-After header โ back off and retry, or call get_subscribe_link for higher limits.
Returns: count and results[] โ per airline: airline_name, iata_code, icao_code, awb_prefix[], callsign, country, has_cargo, aliases and per-record verification fields โ under result, plus confidence, _source and citation (the FreightUtils v1 response envelope).
Limitations: this dataset's provenance is pending independent verification (the envelope's provenance_status says so) โ confirm operationally critical codes with IATA/ICAO or the carrier.
Related: airport_lookup (searches AIRPORTS, not carriers), validate (checks an AWB number's check digit and names its airline from this dataset).
Parameters5
query
string
optional
General search (name, code, prefix or country โ min 2 chars)
Look up an airport by IATA code (3 letters, e.g. "LHR"), ICAO code (4 chars, e.g. "EGLL"), or free-text name/city search (e.g. "heathrow"). Covers 85,555 airports worldwide (OurAirports, public domain, cross-checked vs OpenFlights + Wikidata).
Provide ONE of iata, icao, or query; the optional type filter narrows results. Behavior: read-only; exact code hits return one record; ambiguous name searches return ranked candidates (exact codes first, then larger airports) with match quality reported via the envelope's confidence (basis match_quality); an unknown code errors with a not-found message. Rate-limited (anonymous use: 25 requests/day per IP): a 429 error body carries retry_after_seconds and a Retry-After header โ back off and retry, or call get_subscribe_link for higher limits.
Returns: count and results[] โ per airport: IATA + ICAO/ident, name, type (large/medium/small/heliport/closed/seaplane), municipality, region, country, latitude/longitude and elevation_ft โ under result, plus confidence, _source and citation (the FreightUtils v1 response envelope).
Limitations: reference data only โ not for navigation; verify operationally critical codes with IATA / ICAO.
Related: nearest_airport (find airports FROM a coordinate), airline_lookup (searches CARRIERS / AWB prefixes, not airports), unlocode_lookup (general transport locations, of which airports are one function).
Find the airports nearest to a caller-provided latitude/longitude, sorted by great-circle (haversine) distance with distance_km on each result. Searches 85,555 airports (OurAirports, public domain).
Provide latitude and longitude (decimal degrees); optional radius_km, max_results (1-50, default 10) and type filter (e.g. large_airport only). Coordinates are INPUT only โ nothing is stored or logged.
Behavior: deterministic distance sort; confidence reflects proximity and airport size (a large airport within 25 km scores high; closed/heliport/seaplane results cap lower). This tool does NOT geocode place names and does NOT compute routes โ pass coordinates you already hold. Rate-limited (anonymous use: 25 requests/day per IP): a 429 error body carries retry_after_seconds and a Retry-After header โ back off and retry, or call get_subscribe_link for higher limits.
Returns: count and results[] (the airport record plus distance_km) under result, plus confidence, _source and citation (the FreightUtils v1 response envelope).
Limitations: reference data only โ not for navigation; verify codes with IATA / ICAO.
Related: airport_lookup (exact code or name lookup, no distance), unlocode_lookup (named transport-location search).
Resolve an arbitrary freight identifier โ one opaque string in, typed and cited candidates out. The agent front door: when you hold an identifier-ish token ("176", "UN1845", "NLRTM", "FOB", "22G1", "MSKU1100810", "D/E") and do not know which lookup tool fits, call this FIRST and follow the candidate's api_url / canonical_url (or the matching sibling tool) for depth.
Provide q: ONE identifier (single token, max 32 chars). Thirteen grammars all run โ UN numbers, AWB prefixes, airline IATA/ICAO, airport IATA/ICAO, UN/LOCODE, ISO 6346 container numbers (check digit computed), HS codes (6-10 digits; national lines resolve at their 6-digit international parent), Incoterms, ADR tunnel codes, ULD serials, ISO container size/type codes. Ambiguity is the product: colliding grammars return MULTIPLE ranked candidates ("LHR" is Heathrow AND an Egyptian carrier's ICAO), never a silent guess.
Behavior: deterministic โ normalize (trim, uppercase, collapse spaces/dashes, strip a UN prefix), match ALL grammars, rank by record-hit > verification status > static dataset prior (airlines/adr/unlocode first) > stable tiebreak; every candidate carries rank_basis so the ordering is inspectable. Zero candidates is a VALID result (count 0 + note), never an error. A failed container check digit returns a candidate with valid:false rather than dropping it. Rate-limited (anonymous use: 25 requests/day per IP): a 429 error body carries retry_after_seconds and a Retry-After header โ back off and retry, or call get_subscribe_link for higher limits.
Returns: query, normalized, count and candidates[] โ each with entity_type, identifier_type, value_normalized, summary, record (the core fields the matching dataset holds), verification_status + verification_basis, rank_basis, canonical_url, api_url and a per-candidate dataset citation โ under result, plus confidence, _source and citation (the FreightUtils v1 response envelope).
Limitations: v1 is SINGLE-TOKEN resolution, not free-text extraction โ pass one identifier, not a manifest line; SCAC/BIC codes are not yet covered; a match asserts the identifier is known/well-formed, not that a shipment exists.
Related: every lookup tool this resolves into โ adr_lookup, airline_lookup, airport_lookup, unlocode_lookup, hs_code_lookup, incoterms_lookup, container_lookup, uld_lookup, validate.
Parameters1
q
string
required
One freight identifier โ e.g. "176", "UN1845", "NLRTM", "FOB", "LHR", "22G1", "MSKU1100810", "090111", "AKE12345AB", "D/E".
Get ISO shipping-container specifications, with optional load-fit maths. Covers 10 types: 20ft/40ft standard, 40ft and 45ft high-cube, 20ft/40ft reefer, 20ft/40ft open-top and 20ft/40ft flat-rack.
Provide type as a slug (e.g. "20ft-standard", "40ft-high-cube") for one container's record; omit it to list all 10. Add item dimensions (item_length_cm/width_cm/height_cm, optional item_weight_kg and item_quantity) to also compute how many such items fit.
Behavior: read-only reference data with per-record provenance (sources, audited_at, decision_rationale); an unknown type errors with the valid slug list. Fit calculations are geometric best-effort โ they do not model load distribution, securing or mixed cargo. Rate-limited (anonymous use: 25 requests/day per IP): a 429 error body carries retry_after_seconds and a Retry-After header โ back off and retry, or call get_subscribe_link for higher limits.
Returns: the container record โ internal/external/door dimensions (cm), capacity_cbm, tare_weight_kg, max_gross_kg, max_payload_kg and euro/GMA pallet counts โ under result, plus confidence, _source and citation (the FreightUtils v1 response envelope).
Limitations: manufacturer-typical specs, provenance pending independent verification (the envelope's provenance_status says so) โ actual equipment varies by lessor and line; confirm against the carrier's equipment guide.
Related: validate (checks a container NUMBER's ISO 6346 check digit โ not specs), cbm_calculator / consignment_calculator (the cargo volume to fill it), uld_lookup (the air-freight equivalent).
Parameters1
type
string
optional
Container slug (e.g., "20ft-standard", "40ft-high-cube"). Omit to list all.
Search 6,940 WCO Harmonized System (HS 2022) commodity codes โ the 6-digit international customs classification layer. The first 2 digits are the chapter, 4 the heading, 6 the subheading.
Provide ONE of: query (free-text description search, min 2 chars), code (2-6 digit lookup, returns the code plus its hierarchy), or section (Roman numeral I-XXI to browse a section).
Behavior: read-only; description search is keyword-based against official HS descriptions, so everyday product words can return zero rows โ count 0 with an empty results[] is a valid answer (e.g. "laptop" and "computers" find nothing; "automatic data" matches the official phrasing "automatic data processing machines"); prefer the formal tariff wording. Rate-limited (anonymous use: 25 requests/day per IP): a 429 error body carries retry_after_seconds and a Retry-After header โ back off and retry, or call get_subscribe_link for higher limits.
Returns: the query/code echo, count and results[] (hscode, description and hierarchy context) under result, plus confidence, _source and citation (the FreightUtils v1 response envelope).
Limitations: the 6-digit international level only โ national tariff lines (8-10 digits) and duty rates are set per country; classification here is indicative, not a binding ruling.
Related: uk_duty_calculator (duty/VAT for a code found here), ics2_check (EU ENS goods-description quality โ a different check entirely).
Look up the 11 Incoterms 2020 trade rules โ who pays for transport, insurance and customs clearance, and where risk transfers from seller to buyer. 7 rules work for any transport mode (EXW, FCA, CPT, CIP, DAP, DPU, DDP); 4 are sea/inland-waterway only (FAS, FOB, CFR, CIF).
Provide code for one rule, category (any_mode | sea_only) for a filtered list, or neither to list all 11. Behavior: read-only reference; an unknown code errors with the valid code list. Rate-limited (anonymous use: 25 requests/day per IP): a 429 error body carries retry_after_seconds and a Retry-After header โ back off and retry, or call get_subscribe_link for higher limits.
Returns: the rule record โ name, category, summary, seller_responsibility, buyer_responsibility, risk_transfer, cost_transfer, insurance, export/import clearance, best_for and watch_out โ under result, plus confidence, _source and citation (the FreightUtils v1 response envelope).
Limitations: summarised guidance on ICC Incoterms 2020; the ICC publication is the binding text and specific contract wording prevails.
Related: uk_duty_calculator (accepts an incoterm when composing the CIF value), shipment_summary (composite analysis).
Calculate how many identical boxes fit on a pallet: boxes per layer (trying 90-degree rotation when allowed), layer count within the max height, totals, volume utilisation and weight capping.
Behavior: deterministic geometric packing of one box size in aligned rows and columns โ it does not model interlocked or mixed-orientation patterns; weight_limited reports when max_payload_kg caps the count below the geometric fit; pallet_deck_height_cm defaults to 15. Missing or non-positive dimensions error naming the parameter. Rate-limited (anonymous use: 25 requests/day per IP): a 429 error body carries retry_after_seconds and a Retry-After header โ back off and retry, or call get_subscribe_link for higher limits.
Returns: boxes_per_layer, layers, total_boxes, orientation, boxes_per_row/col, usable_height_cm, utilisation_percent, total_box_volume_cbm, wasted_space_cbm and the weight fields under result, plus confidence, _source and citation (the FreightUtils v1 response envelope).
Limitations: a theoretical best-effort fit โ real stacking obeys carton strength, overhang and load-stability rules it does not model.
Related: ldm_calculator (pallets into trailer length), vehicle_lookup (pallet capacity per vehicle), container_lookup (pallets into containers).
Convert freight and logistics units: weight (kg, lbs, oz, tonnes, short_tons, long_tons), volume (cbm, cuft, cuin, litres, gal_us, gal_uk), length (cm, inches, m, feet, mm), plus two freight-specific targets valid only FROM cbm โ chargeable_kg (air volumetric weight at the IATA 6,000 divisor, 1 CBM = 166.67 kg) and freight_tonnes (sea W/M, 1 CBM = 1 freight tonne).
Behavior: deterministic; the response names both units and states the formula used. Cross-dimension conversions (e.g. kg to litres) and freight targets from a non-cbm source error with the accepted-unit list. Note: short ton (US) = 2,000 lb, long ton (UK) = 2,240 lb, metric tonne = 2,204.6 lb. Rate-limited (anonymous use: 25 requests/day per IP): a 429 error body carries retry_after_seconds and a Retry-After header โ back off and retry, or call get_subscribe_link for higher limits.
Returns: input {value, unit, name}, result {value, unit, name}, formula and note under result, plus confidence, _source and citation (the FreightUtils v1 response envelope).
Related: cbm_calculator (dimensions to volume first), chargeable_weight_calculator (proper air billing weight with pieces and a custom divisor).
Parameters3
value
number
required
Value to convert
from
string
required
Source unit โ weight (kg, lbs, oz, tonnes, short_tons, long_tons), volume (cbm, cuft, cuin, litres, gal_us, gal_uk) or length (cm, inches, m, feet, mm)
to
string
required
Target unit โ any source unit, plus the freight targets chargeable_kg and freight_tonnes (only valid from cbm)
Raw schema
{
"type": "object",
"properties": {
"value": {
"type": "number",
"description": "Value to convert"
},
"from": {
"type": "string",
"enum": [
"kg",
"lbs",
"oz",
"tonnes",
"short_tons",
"long_tons",
"cbm",
"cuft",
"cuin",
"litres",
"gal_us",
"gal_uk",
"cm",
"inches",
"m",
"feet",
"mm"
],
"description": "Source unit โ weight (kg, lbs, oz, tonnes, short_tons, long_tons), volume (cbm, cuft, cuin, litres, gal_us, gal_uk) or length (cm, inches, m, feet, mm)"
},
"to": {
"type": "string",
"enum": [
"kg",
"lbs",
"oz",
"tonnes",
"short_tons",
"long_tons",
"cbm",
"cuft",
"cuin",
"litres",
"gal_us",
"gal_uk",
"cm",
"inches",
"m",
"feet",
"mm",
"chargeable_kg",
"freight_tonnes"
],
"description": "Target unit โ any source unit, plus the freight targets chargeable_kg and freight_tonnes (only valid from cbm)"
}
},
"required": [
"value",
"from",
"to"
],
"$schema": "http://json-schema.org/draft-07/schema#"
}
consignment_calculator
Calculate per-line and grand totals for a multi-item mixed consignment: CBM, loading metres (LDM), volumetric weight, and the mode-specific chargeable figure (air chargeable weight, sea revenue tonnes, road LDM), plus objective advisory flags.
Provide mode (sea | air | road, default road) and either lines[] (canonical โ per line: quantity, dims {l,w,h,unit}, weight {value,unit}, optional description / hs_code / un_number / stackable) or the legacy flat items[] (dimensions in cm, weight in kg). Air uses an IATA volumetric divisor (default 6000, settable via options.air_volumetric_divisor); options.container_number / options.awb_number add a check-digit sanity flag.
Behavior: deterministic; flags are advisory only โ implausible density, mode/option mismatch, dangerous-goods presence by UN number against ADR 2025, and container/AWB check-digit validity โ and never state that a shipment is permitted or compliant. Invalid lines error naming the offending field. Canonical schema: https://www.freightutils.com/schema/consignment.v1.json. Rate-limited (anonymous use: 25 requests/day per IP): a 429 error body carries retry_after_seconds and a Retry-After header โ back off and retry, or call get_subscribe_link for higher limits.
Returns: schema_version, mode, per_line[] (cbm, gross_weight_kg, density, volumetric_weight_kg, ldm, revenue_tonnes, chargeable_weight_kg), totals (incl. billing_basis) and flags[] under result, plus confidence, _source and citation (the FreightUtils v1 response envelope).
Limitations: best-effort deterministic calculation and reference data โ not regulatory, customs or dangerous-goods compliance advice; classification, documentation and carrier acceptance remain your responsibility.
Related: cbm_calculator / chargeable_weight_calculator / ldm_calculator (single-figure versions), shipment_summary (adds vehicle/container suggestion and duty estimates), adr_lookup (what a flagged UN number is).
Parameters4
mode
string
optional
Transport mode: sea | air | road (default road). Selects the chargeable-weight basis.
{
"type": "object",
"properties": {
"mode": {
"description": "Transport mode: sea | air | road (default road). Selects the chargeable-weight basis.",
"type": "string",
"enum": [
"sea",
"air",
"road"
]
},
"lines": {
"description": "Canonical consignment lines (preferred). Each: { quantity, dims:{l,w,h,unit}, weight:{value,unit}, optional description / hs_code / un_number / stackable }.",
"minItems": 1,
"maxItems": 50,
"type": "array",
"items": {
"type": "object",
"properties": {
"description": {
"description": "Optional item label",
"type": "string",
"maxLength": 200
},
"quantity": {
"type": "integer",
"exclusiveMinimum": 0,
"maximum": 100000,
"description": "Number of identical pieces"
},
"dims": {
"type": "object",
"properties": {
"l": {
"type": "number",
"exclusiveMinimum": 0,
"description": "Length in the given unit"
},
"w": {
"type": "number",
"exclusiveMinimum": 0,
"description": "Width in the given unit"
},
"h": {
"type": "number",
"exclusiveMinimum": 0,
"description": "Height in the given unit"
},
"unit": {
"type": "string",
"enum": [
"mm",
"cm",
"m",
"in"
],
"description": "Dimension unit: mm | cm | m | in"
}
},
"required": [
"l",
"w",
"h",
"unit"
],
"additionalProperties": false
},
"weight": {
"type": "object",
"properties": {
"value": {
"type": "number",
"exclusiveMinimum": 0,
"description": "Gross weight per piece in the given unit"
},
"unit": {
"type": "string",
"enum": [
"kg",
"g",
"t",
"lb"
],
"description": "Weight unit: kg | g | t | lb"
}
},
"required": [
"value",
"unit"
],
"additionalProperties": false
},
"hs_code": {
"description": "Optional HS commodity code",
"type": "string",
"pattern": "^\\d{6,10}$"
},
"un_number": {
"description": "Optional UN number for dangerous-goods reference",
"type": "string",
"pattern": "^(UN)?\\d{4}$"
},
"stackable": {
"description": "Whether the line may be stacked two-high (halves its loading-metre footprint)",
"type": "boolean"
}
},
"required": [
"quantity",
"dims",
"weight"
],
"additionalProperties": false
}
},
"items": {
"description": "Deprecated flat alias โ dimensions in cm, weight in kg. Prefer \"lines\". Provide lines OR items.",
"minItems": 1,
"maxItems": 50,
"type": "array",
"items": {
"type": "object",
"properties": {
"description": {
"description": "Item description",
"type": "string"
},
"length": {
"type": "number",
"exclusiveMinimum": 0,
"description": "Length in cm"
},
"width": {
"type": "number",
"exclusiveMinimum": 0,
"description": "Width in cm"
},
"height": {
"type": "number",
"exclusiveMinimum": 0,
"description": "Height in cm"
},
"quantity": {
"description": "Number of pieces (default 1)",
"type": "integer",
"exclusiveMinimum": 0,
"maximum": 9007199254740991
},
"gross_weight": {
"type": "number",
"exclusiveMinimum": 0,
"description": "Gross weight per piece in kg"
},
"stackable": {
"description": "Can the item be stacked?",
"type": "boolean"
},
"pallet_type": {
"description": "Pallet type (informational)",
"type": "string",
"enum": [
"none",
"euro",
"uk",
"us",
"custom"
]
},
"un_number": {
"description": "Optional UN number for dangerous-goods reference",
"type": "string"
},
"hs_code": {
"description": "Optional HS commodity code",
"type": "string"
}
},
"required": [
"length",
"width",
"height",
"gross_weight"
]
}
},
"options": {
"description": "Optional: { air_volumetric_divisor, container_number, awb_number }.",
"type": "object",
"properties": {
"air_volumetric_divisor": {
"description": "IATA volumetric divisor in cmยณ/kg (default 6000). Only affects air.",
"type": "number",
"exclusiveMinimum": 0,
"maximum": 10000
},
"container_number": {
"description": "ISO 6346 container number โ check-digit validated, advisory only",
"type": "string",
"maxLength": 20
},
"awb_number": {
"description": "IATA 11-digit air waybill number โ check-digit validated, advisory only",
"type": "string",
"maxLength": 20
}
},
"additionalProperties": false
}
},
"$schema": "http://json-schema.org/draft-07/schema#"
}
unlocode_lookup
Search 116,232 UN/LOCODE transport locations worldwide โ ports, airports, rail and road terminals, inland container depots and border crossings. Codes are 5 characters: a 2-letter ISO country code + a 3-character location code (GBLHR = London Heathrow, NLRTM = Rotterdam).
Provide code for an exact record, or query (name search, min 2 chars) optionally narrowed by country and function_type; limit caps results (default 20, max 100).
Behavior: read-only; exact code hits are provenance-based while fuzzy name hits report match quality via the envelope's confidence (basis match_quality); an unknown code errors with a not-found message. Rate-limited (anonymous use: 25 requests/day per IP): a 429 error body carries retry_after_seconds and a Retry-After header โ back off and retry, or call get_subscribe_link for higher limits.
Returns: the location record(s) โ code, name and name_ascii, country, subdivision, functions[], status, coordinates {lat, lon} and iata_code where assigned โ under result, plus confidence, _source and citation (the FreightUtils v1 response envelope).
Limitations: an administrative code list (UNECE UN/LOCODE 2025-1) โ confirm operational status and coordinates with the port or authority before critical use.
Related: airport_lookup (airport-specific records including ICAO codes), nearest_airport (find airports by coordinates).
Parameters5
query
string
optional
Search by name or code (e.g. "Rotterdam", "GBLHR", "LHR")
code
string
optional
Exact UN/LOCODE lookup (e.g. "GBLHR", "NLRTM")
country
string
optional
ISO 2-letter country code filter (e.g. "GB", "NL")
Estimate UK import duty and VAT for a commodity code using the LIVE GOV.UK Trade Tariff โ rates are fetched per request, not from a static table. The CIF value is composed from customs_value + freight_cost + insurance_cost; duty = CIF x the duty rate for the origin country; VAT (typically 20%) applies on the duty-inclusive value.
Provide commodity_code (6-10 digits), origin_country (ISO-2) and customs_value in GBP; freight_cost, insurance_cost and incoterm are optional refinements.
Behavior: live lookup plus deterministic arithmetic on the returned rate; an unknown or non-declarable commodity code errors with HMRC's message (a 6-digit code may need extending to its 8/10-digit declarable line); origin-dependent measures the tariff cannot resolve automatically surface in warnings. Rate-limited (anonymous use: 25 requests/day per IP): a 429 error body carries retry_after_seconds and a Retry-After header โ back off and retry, or call get_subscribe_link for higher limits.
Returns: commodity_code and description, origin country, cif_value, duty_rate (+ percent), duty_amount, vat_rate, vat_amount, total_import_taxes, total_landed_cost and warnings under result; validity.as_of marks the live-rate timestamp; plus confidence, _source and citation (the FreightUtils v1 response envelope).
Limitations: an estimate, not a customs ruling โ excise, quotas, anti-dumping measures, reliefs and origin-proof requirements can change the outcome; confirm with a customs broker or HMRC before relying on it.
Related: hs_code_lookup (find the 6-digit code first), incoterms_lookup (who actually pays these costs).
Composite shipment analysis in one call: volume (CBM), gross and chargeable weight, road LDM with pallet spaces and a vehicle suggestion (road mode), volumetric weight (air), revenue tonnes with a container suggestion (sea), dangerous-goods presence for items carrying un_number, and UK duty estimates for items carrying hs_code + customs_value.
Provide mode (road | air | sea | multimodal) and items[] (dims in cm, weight in kg, quantity; optional stackable, pallet_type, hs_code, un_number, customs_value); origin/destination and incoterm refine the duty leg.
Behavior: calls the ldm_calculator, adr_lookup and uk_duty_calculator engines directly; CBM, volumetric weight and revenue tonnes are the same arithmetic inline rather than a call out. Road LDM uses the 2.40 m loading-metre convention divisor and, like ldm_calculator, treats an item with no stackable flag as NOT stacked. modeSpecific.palletSpaces is pallet FLOOR POSITIONS (the figure ldm_calculator reports); palletRows is the separate row count. Sections that cannot run (e.g. duty without a customs value) surface in warnings instead of failing the whole call. Rate-limited (anonymous use: 25 requests/day per IP): a 429 error body carries retry_after_seconds and a Retry-After header โ back off and retry, or call get_subscribe_link for higher limits.
Returns: mode, itemCount, totals {pieces, grossWeight, volumeCBM, chargeableWeight, billingBasis}, modeSpecific (LDM / pallet floor positions / pallet rows / suggested vehicle, or revenue tonnes / container), warnings and dataVersion (road mode attributes the vehicle dataset and the LDM divisor) under result โ note this composite's result uses camelCase field names (legacy shape); plus confidence, _source and citation (the FreightUtils v1 response envelope).
Limitations: a planning summary, not a quotation or compliance determination.
Related: consignment_calculator (canonical snake_case lines[] shape with advisory flags), cbm_calculator, chargeable_weight_calculator, ldm_calculator, adr_lookup, uk_duty_calculator. ldm_calculator, adr_lookup and uk_duty_calculator are the engines this actually calls; the rest are the single-purpose equivalents of arithmetic it does inline.
Parameters7
mode
string
required
Transport mode
items
array
required
Array of shipment items with dimensions, weight, and optional HS/UN codes
origin
object
optional
Origin location โ ISO country code and optional UN/LOCODE
destination
object
optional
Destination location โ ISO country code and optional UN/LOCODE
Optional insurance cost in GBP for duty calculation
Raw schema
{
"type": "object",
"properties": {
"mode": {
"type": "string",
"enum": [
"road",
"air",
"sea",
"multimodal"
],
"description": "Transport mode"
},
"items": {
"type": "array",
"items": {
"type": "object",
"properties": {
"description": {
"type": "string"
},
"length": {
"type": "number",
"exclusiveMinimum": 0,
"description": "Length cm"
},
"width": {
"type": "number",
"exclusiveMinimum": 0,
"description": "Width cm"
},
"height": {
"type": "number",
"exclusiveMinimum": 0,
"description": "Height cm"
},
"weight": {
"type": "number",
"description": "Gross weight kg per item"
},
"quantity": {
"type": "integer",
"exclusiveMinimum": 0,
"maximum": 9007199254740991
},
"stackable": {
"description": "Whether this item can be stacked (affects pallet fitting calc)",
"type": "boolean"
},
"pallet_type": {
"description": "Pallet standard the item sits on, if any",
"type": "string",
"enum": [
"euro",
"uk",
"us",
"custom",
"none"
]
},
"hs_code": {
"type": "string"
},
"un_number": {
"type": "string"
},
"adr_quantity": {
"description": "ADR 1.1.3.6.3 quantity for this dangerous-goods line, in adr_quantity_unit. SEPARATE from weight, which is gross package mass โ 1.1.3.6.3 counts none of its four categories that way. Supply both on EVERY dangerous-goods line and adrFlags.totalPoints is calculated; omit either and it stays null.",
"type": "number",
"exclusiveMinimum": 0
},
"adr_quantity_unit": {
"description": "Dimension of adr_quantity. Checked against the dimension 1.1.3.6.3 counts for the row โ a litres row given kilograms still withholds the total.",
"type": "string",
"enum": [
"L",
"kg"
]
},
"customs_value": {
"type": "number"
}
},
"required": [
"length",
"width",
"height",
"weight",
"quantity"
]
},
"description": "Array of shipment items with dimensions, weight, and optional HS/UN codes"
},
"origin": {
"description": "Origin location โ ISO country code and optional UN/LOCODE",
"type": "object",
"properties": {
"country": {
"type": "string"
},
"locode": {
"type": "string"
}
},
"required": [
"country"
]
},
"destination": {
"description": "Destination location โ ISO country code and optional UN/LOCODE",
"type": "object",
"properties": {
"country": {
"type": "string"
},
"locode": {
"type": "string"
}
},
"required": [
"country"
]
},
"incoterm": {
"description": "Incoterms 2020 three-letter code (e.g. 'DAP', 'EXW', 'FOB')",
"type": "string"
},
"freight_cost": {
"description": "Optional freight cost in GBP for duty calculation",
"type": "number"
},
"insurance_cost": {
"description": "Optional insurance cost in GBP for duty calculation",
"type": "number"
}
},
"required": [
"mode",
"items"
],
"$schema": "http://json-schema.org/draft-07/schema#"
}
uld_lookup
Look up air-cargo ULD (Unit Load Device) specifications โ 16 types spanning lower-deck containers (AKE/LD3 and family), main-deck pallets (PMC, PAG and family) and temperature-controlled units. Each record carries external/internal/door dimensions (cm), tare and max gross weight (kg), usable volume (mยณ), deck position and compatible aircraft.
Provide type as an IATA code ("AKE", "PMC") or slug ("ake-ld3"); omit it to list all 16; category (container | pallet | special) and deck (lower | main) filter the list.
Behavior: read-only; an unknown type errors with the valid list; per-record provenance (sources, audited_at, decision_rationale) is included. Rate-limited (anonymous use: 25 requests/day per IP): a 429 error body carries retry_after_seconds and a Retry-After header โ back off and retry, or call get_subscribe_link for higher limits.
Returns: the ULD record (or filtered list) under result, plus confidence, _source and citation (the FreightUtils v1 response envelope).
Limitations: specs are compiled from manufacturer and carrier-published sources with โฅ7 cited sources per record. Provenance is PENDING, not verified โ read the envelope's provenance_status rather than this sentence. Second-agent coverage is now COMPLETE โ every cited record-URL pairing has been opened and verdicted by a second agent, and 145 of 148 citations carry a timestamped read (the 3 without one were never opened, and say so). COVERAGE IS NOT AGREEMENT, which is why provenance is still pending: reading every page is what made the disagreements visible, not what resolved them. The second agent also WITHDRAWS stamps โ pages a first pass had confirmed turned out not to list the code, or to disagree once somebody read the words around them โ so treat an unstamped citation as evidence that was tried and failed, not evidence not yet gathered. CORROBORATION IS COUNTED BY PUBLISHER, NOT BY URL: the 148 citations resolve to 125 distinct sources, because several records cite one publisher at several of its own addresses (one carrier's pallet table appears in three of its documents) and several forwarders republish a single upstream template. Two citations of the same source cannot corroborate each other, so a long source list is not the same as a well-corroborated record. Treat tare_weight with particular caution: it is confirmed by no non-tertiary source on 13 of the 16 records. PGA's 565 kg is now read-confirmed by one carrier (Cathay, basis stated on the page as including nets) while two other carrier pages publish 535 kg and 505-545 kg on that same basis, so it is the top of a contested band rather than an agreed figure. Confidence is medium and a PROVENANCE_PENDING advisory rides every response. Pallet records (PMC, PAG, PGA, PLA, PAJ, PMCQ7) have NO internal dimensions โ a pallet has no walls or roof; read max_build_up_height_cm for the aircraft contour ceiling and do not multiply dimensions to get a volume. Airline-specific ULD variants still differ; confirm operationally critical dimensions with the carrier.
Related: chargeable_weight_calculator (what the cargo inside is billed at), container_lookup (the sea-freight equivalent), airline_lookup (whose aircraft it flies on).
Parameters3
type
string
optional
ULD code (e.g., "AKE", "PMC") or slug (e.g., "ake-ld3"). Omit to list all.
Look up road-freight vehicle and trailer specifications โ 17 types: EU articulated trailers (standard/mega curtainsider, box, reefer, double-deck, flatbed, low-loader), US 53ft/48ft dry vans, rigid trucks (7.5-26 t) and vans (Luton, Transit, Sprinter). Each record carries internal dimensions, payload and gross weights, euro/UK pallet capacity, axle configuration and features.
Provide slug (e.g. "standard-curtainsider") for one record; omit it to list all 17; category (articulated | rigid | van) and region (EU | US) filter the list.
Behavior: read-only; an unknown slug errors with the valid list; per-record provenance (sources, audited_at, decision_rationale) is included. Rate-limited (anonymous use: 25 requests/day per IP): a 429 error body carries retry_after_seconds and a Retry-After header โ back off and retry, or call get_subscribe_link for higher limits.
Returns: the vehicle record (or filtered list) under result, plus confidence, _source and citation (the FreightUtils v1 response envelope).
Limitations: typical specs, provenance pending independent verification (the envelope's provenance_status says so) โ real equipment varies by operator and build; legal payload is set by the vehicle's plated weights.
Related: ldm_calculator (whether a pallet load fits), pallet_fitting_calculator, consignment_calculator.
Parameters3
slug
string
optional
Vehicle slug (e.g., "standard-curtainsider"). Omit to list all.
Get the URL where the user can subscribe to FreightUtils Pro for higher API limits (50,000 requests/month). Use when the user asks how to upgrade or about pricing, or after any other tool errors with a 429 rate_limited body.
Behavior: static local response โ no API call, never rate-limited.
Returns: url, tier, monthly_limit, monthly_price, currency and note under result. Hand the URL to the USER to open in a browser โ agents must NOT attempt to complete the subscription themselves.
Check whether dangerous goods qualify for ADR Limited Quantity (LQ, ADR 3.4) or Excepted Quantity (EQ, ADR 3.5) relief. LQ compares each item's per-inner-packaging quantity against that substance's LQ maximum; EQ resolves the substance's E-code (E0-E5) and checks the per-inner limit, plus the per-outer limit when inner_packaging_qty is given.
Provide mode ("lq" or "eq") and 1-20 items, each with un_number, quantity and unit โ ml or L for liquids, g or kg for solids; quantity is per INNER packaging, not the whole load.
Unit families: column (7a) states the limit in ONE dimension โ a mass for some entries, a volume for others โ and ADR supplies no density, so a mass quantity against a volume limit (or the reverse) CANNOT be compared. Those items return status 'inconclusive' with the dimension named, never a pass or a fail, and a batch holding any inconclusive item never reads overall_status 'qualifies'. Send the quantity in the unit given by lq_limit_unit to get a verdict. Multi-variant UNs: a UN number with more than one ADR Table A row (packing group / concentration variant โ e.g. UN 1789 PG II LQ 1 L vs PG III LQ 5 L) needs packing_group (I|II|III) or variant_index (from adr_lookup) on that item to pin one row. Without a disambiguator the tool returns blocking_errors[AMBIGUOUS_UN_VARIANT] + human_review_required + candidates[] (each candidate's variant_index, packing_group, proper_shipping_name, limited_quantity, excepted_quantity) and NO verdict, rather than silently checking the wrong packing group. Single-row UNs are unchanged.
Behavior: deterministic reference check; each item gets a status and reason (an LQ value of "0" or code E0 means the relief is not permitted for that substance), with overall_status and summary counts across the batch. Table A rows listed "NOT SUBJECT TO ADR" (e.g. UN 1845 dry ice) get item status not_subject โ outside ADR scope, neither a pass nor a fail โ and an all-not-subject batch returns overall_status not_applicable; "CARRIAGE PROHIBITED" rows are not_permitted with the prohibition stated in reason. Rate-limited (anonymous use: 25 requests/day per IP): a 429 error body carries retry_after_seconds and a Retry-After header โ back off and retry, or call get_subscribe_link for higher limits.
Returns: mode, overall_status (qualifies | does_not_qualify | partial | not_applicable | inconclusive), items[] (un_number, variant_index, substance, class, packing_group, lq_limit or eq_code, quantity_entered, status, reason, and scope flags where applicable), summary {total_items, qualifying, exceeding, not_permitted, not_subject?, inconclusive?} and the ADR chapter references under result โ or, when a UN is ambiguous, human_review_required + candidates[] with blocking_errors, plus confidence, _source and citation (the FreightUtils v1 response envelope).
Limitations: a quantity-threshold check only โ LQ/EQ relief also requires packaging, marking and documentation conformity that this tool does not assess; not legal advice, verify against the current UNECE ADR text.
Related: adr_lookup (the per-substance LQ/EQ values + variant_index), adr_exemption_calculator (the 1.1.3.6 load-points route instead).
{
"type": "object",
"properties": {
"mode": {
"type": "string",
"enum": [
"lq",
"eq"
],
"description": "Check mode: 'lq' (Limited Quantity, ADR 3.4) or 'eq' (Excepted Quantity, ADR 3.5)"
},
"items": {
"minItems": 1,
"maxItems": 20,
"type": "array",
"items": {
"type": "object",
"properties": {
"un_number": {
"type": "string",
"pattern": "^(UN)?\\d{4}$",
"description": "UN number โ 4 digits, optionally \"UN\"-prefixed; explosives keep the leading zero. Examples: \"1203\", \"UN1263\", \"0004\"."
},
"quantity": {
"type": "number",
"exclusiveMinimum": 0,
"description": "Quantity per inner packaging, expressed in the chosen unit. Example: 0.5."
},
"unit": {
"type": "string",
"enum": [
"ml",
"L",
"g",
"kg"
],
"description": "Unit for the quantity: \"ml\" or \"L\" for liquids, \"g\" or \"kg\" for solids."
},
"inner_packaging_qty": {
"description": "EQ mode only: number of inner packagings per outer package, for the per-outer limit check. Default 1. Example: 10.",
"type": "integer",
"exclusiveMinimum": 0,
"maximum": 9007199254740991
},
"packing_group": {
"description": "Packing group (I, II or III) โ only needed to disambiguate a UN with more than one ADR Table A row (e.g. UN 1789: PG II LQ 1 L vs PG III LQ 5 L). Ignored for single-row UNs.",
"type": "string",
"enum": [
"I",
"II",
"III"
]
},
"variant_index": {
"description": "ADR Table A variant index (as returned by adr_lookup) โ pins one row when a UN has several variants that share a packing group (e.g. concentration bands). Ignored for single-row UNs.",
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
}
},
"required": [
"un_number",
"quantity",
"unit"
]
},
"description": "Items to check (1โ20 per call)."
}
},
"required": [
"mode",
"items"
],
"$schema": "http://json-schema.org/draft-07/schema#"
}
emissions_calculator
Estimate freight transport greenhouse-gas emissions (kgCO2e) for a shipment leg, per ISO 14083:2023 / GLEC Framework v3.2: emissions = mass x distance x a published emission-intensity factor (kgCO2e/tonne-km).
Provide mass + distance_km + mode (road | rail | sea | air | inland_waterway); optionally choose sub_mode, region/authority (uk = DEFRA, us = EPA, fr = ADEME) and basis (wtw default, or ttw). IMPORTANT: pass ACTUAL GROSS MASS, not chargeable/volumetric weight (a common air-freight mistake โ see mass_basis in the result). Distance must be provided โ this tool does NOT route, geocode, or compute distances.
Behavior: deterministic given the same factor edition; the fleet-average factor already includes average empty running (see empty_running) โ do NOT add your own empty-return leg; sea and air are low-representativeness generic defaults (real emissions vary materially by vessel/aircraft, load factor and routing โ see representativeness and the result summary). An unknown mode/sub_mode/region returns available:false with the covered options, never a fabricated factor. Rate-limited (anonymous use: 25 requests/day per IP): a 429 error body carries retry_after_seconds and a Retry-After header โ back off and retry, or call get_subscribe_link for higher limits.
Returns: well-to-wheel AND tank-to-wheel emissions where the factor has both, the exact factor used (value, authority, edition), the tonne-km activity and a per-result _source citing BOTH the ISO method and the specific open factor, all under result, plus confidence, _source and citation (the FreightUtils v1 response envelope).
Limitations: best-effort reference estimate from open factors (DEFRA / EPA / ADEME) โ NOT a verified or audited carbon report.
Related: distinct from cbm_calculator / ldm_calculator / chargeable_weight_calculator (those size or bill a shipment; this one estimates its CO2e).
Parameters7
mass
number
required
Shipment mass, expressed in mass_unit. Example: 1000
mass_unit
string
optional
Unit for mass (default: kg)
distance_km
number
required
Transport distance in kilometres โ you provide it; the tool does not route or compute distance
mode
string
required
Transport mode
sub_mode
string
optional
Optional sub-mode / vehicle class (e.g. "articulated", "container ship", "long-haul"). Omit for the representative default; an unknown value returns available:false with the covered list.
region
string
optional
Factor source/region: uk = DEFRA, us = EPA, fr = ADEME. Default is per-mode.
basis
string
optional
Emissions basis: wtw = well-to-wheel incl. upstream energy (default), ttw = tank-to-wheel / operation only
Raw schema
{
"type": "object",
"properties": {
"mass": {
"type": "number",
"exclusiveMinimum": 0,
"description": "Shipment mass, expressed in mass_unit. Example: 1000"
},
"mass_unit": {
"description": "Unit for mass (default: kg)",
"type": "string",
"enum": [
"kg",
"tonnes"
]
},
"distance_km": {
"type": "number",
"exclusiveMinimum": 0,
"description": "Transport distance in kilometres โ you provide it; the tool does not route or compute distance"
},
"mode": {
"type": "string",
"enum": [
"road",
"rail",
"sea",
"air",
"inland_waterway"
],
"description": "Transport mode"
},
"sub_mode": {
"description": "Optional sub-mode / vehicle class (e.g. \"articulated\", \"container ship\", \"long-haul\"). Omit for the representative default; an unknown value returns available:false with the covered list.",
"type": "string"
},
"region": {
"description": "Factor source/region: uk = DEFRA, us = EPA, fr = ADEME. Default is per-mode.",
"type": "string",
"enum": [
"uk",
"us",
"fr"
]
},
"basis": {
"description": "Emissions basis: wtw = well-to-wheel incl. upstream energy (default), ttw = tank-to-wheel / operation only",
"type": "string",
"enum": [
"wtw",
"ttw"
]
}
},
"required": [
"mass",
"distance_km",
"mode"
],
"$schema": "http://json-schema.org/draft-07/schema#"
}
validate
Validate and parse freight identifiers by their public check-digit algorithms: shipping container numbers (ISO 6346), air waybill (AWB) numbers (IATA modulus-7) and IMO ship identification numbers.
Two modes: pass text=<arbitrary string> to find and validate every identifier in it (e.g. a booking-email line), OR pass value=<identifier> + type=<container|awb|imo> to validate one.
Behavior: deterministic check-digit arithmetic; per identifier found it reports type, the normalised form, valid (pass/fail), expected vs actual check digit, and details (container: owner prefix + equipment category; AWB: airline prefix + the operating airline resolved from the AWB-prefix dataset; IMO: the 7-digit number); text mode with no identifiers found returns an empty found[] with a note. Rate-limited (anonymous use: 25 requests/day per IP): a 429 error body carries retry_after_seconds and a Retry-After header โ back off and retry, or call get_subscribe_link for higher limits.
Returns: found[] (each entry with its own _source naming the standard applied) and disclaimer under result, plus confidence, _source and citation (the FreightUtils v1 response envelope).
Limitations: STRUCTURAL ONLY โ a valid check digit means well-formed, NOT that the container, shipment or vessel exists or is active; not a registry or tracking lookup.
Related: container_lookup (container TYPE specs, not numbers), airline_lookup (the AWB-prefix dataset the airline resolution uses).
Parameters3
text
string
optional
Arbitrary string to scan for container / AWB / IMO identifiers (parse mode). Provide this OR value+type.
value
string
optional
A single identifier to validate (typed mode). Requires type.
type
string
optional
Identifier type for value: container = ISO 6346, awb = IATA Air Waybill, imo = IMO ship number.
Raw schema
{
"type": "object",
"properties": {
"text": {
"description": "Arbitrary string to scan for container / AWB / IMO identifiers (parse mode). Provide this OR value+type.",
"type": "string"
},
"value": {
"description": "A single identifier to validate (typed mode). Requires type.",
"type": "string"
},
"type": {
"description": "Identifier type for value: container = ISO 6346, awb = IATA Air Waybill, imo = IMO ship number.",
"type": "string",
"enum": [
"container",
"awb",
"imo"
]
}
},
"$schema": "http://json-schema.org/draft-07/schema#"
}
ics2_check
Check a goods description against the official EU ICS2 stop-words list โ terms the European Commission deems too vague or generic for an entry summary declaration (ENS) goods-description field (data element 18 05 000 000).
Pass description=<goods description>. Behavior: deterministic term matching against the in-force EU list; each flagged term carries a note (a standalone stop-word means automatic rejection, an embedded one means make the description more specific); clean=true means no listed term matched โ it does NOT guarantee acceptance, and no binary accepted/rejected verdict is given. Rate-limited (anonymous use: 25 requests/day per IP): a 429 error body carries retry_after_seconds and a Retry-After header โ back off and retry, or call get_subscribe_link for higher limits.
Returns: the description echo, flagged[] (term + note), clean, caveat and disclaimer under result, plus a _source citing the EU list and legal basis, plus confidence, _source and citation (the FreightUtils v1 response envelope).
Limitations: STRICTLY a reference check โ not an ENS filing, not a customs-compliance determination, not legal advice; the EU list is non-exhaustive and updated periodically.
Related: hs_code_lookup (commodity codes โ a different field of the ENS), uk_duty_calculator (duty/VAT, unrelated to ENS screening). Use BEFORE filing an ENS โ for customs/documentation teams, brokers and agents building filing pipelines.
Parameters1
description
string
required
The goods description to check against the EU ICS2 stop-words list.
Raw schema
{
"type": "object",
"properties": {
"description": {
"type": "string",
"description": "The goods description to check against the EU ICS2 stop-words list."
}
},
"required": [
"description"
],
"$schema": "http://json-schema.org/draft-07/schema#"
}
The neutral freight reference layer for AI agents.
FreightUtils is the neutral freight reference layer for AI agents โ source-backed dangerous-goods, customs, location and freight-calculation data an agent can call and cite, from primary sources (ADR 2025 / UNECE, HS 2022 / WCO, IATA-regulated airline prefixes). Neutral by design: no freight to sell and no carrier to push โ a lookup returns what the named source says, with the citation attached so an agent can inspect it rather than take our word for it, regardless of who carries the load.
This Model Context Protocol server gives AI agents access to 25 freight calculation and reference tools, covering road, air, and sea freight. Built by a UK ADR-certified freight transport planner.
Every response cites its source โ a _source block with the authority, edition, licence where held, and a verification status an agent can read โ and the tools are deterministic, not generated answers. Reference only: never filing, booking, or legal advice, and results state when human review is required (validate is structural check-digit validation only; a clean ics2_check is not ENS acceptance; emissions figures are estimates, not audited reports).
Since 2.11.0, every tool also declares a typed outputSchema and returns structuredContent โ the FreightUtils v1 response envelope: the answer under result, plus confidence, normalized_input, warnings, _source and a ready-to-use citation. The legacy flat JSON text channel is unchanged (byte-identical), so existing text-parsing consumers are unaffected.
Freight CO2e via the ISO 14083 / GLEC distance-based method โ open DEFRA/EPA/ADEME factors (WTW + TTW); use actual gross mass (not chargeable/volumetric); result carries empty_running + representativeness (sea/air = low) + a summary
Dangerous Goods (ADR)
Tool
Description
adr_lookup
2,939 UNECE ADR 2025 entries
adr_exemption_calculator
ADR 1.1.3.6 small load exemption check
adr_lq_eq_check
Limited and Excepted Quantity eligibility
Customs & Tariff
Tool
Description
hs_code_lookup
6,940 Harmonized System tariff codes (HS 2022)
uk_duty_calculator
UK import duty and VAT (live GOV.UK Trade Tariff data)
incoterms_lookup
Incoterms 2020 โ all 11 rules with risk/cost transfer points
ics2_check
Flag EU ICS2 unacceptable goods-description terms (stop-words) before filing an ENS โ reference only
Reference Data
Tool
Description
resolve_reference
Resolve any freight identifier ("176", "UN1845", "NLRTM", "FOB") to typed, ranked, cited candidates โ the agent front door
airline_lookup
6,357 airlines with IATA/ICAO codes and AWB prefixes
unlocode_lookup
116,232+ UN/LOCODE transport locations
airport_lookup
85,555 airports by IATA/ICAO code, name or city (OurAirports)
nearest_airport
Nearest airports to a latitude/longitude, by great-circle distance
uld_lookup
16 air cargo ULD types (LD3, PMC, etc.)
vehicle_lookup
17 road freight vehicles and trailers
Validation
Tool
Description
validate
Parse any text (a booking line, an email) to find & validate every container (ISO 6346), AWB (modulus-7) and IMO number in it โ or validate a single identifier by type
Composite
Tool
Description
shipment_summary
Chains CBM + weight + LDM + ADR + duty in one call
Subscription
Tool
Description
get_subscribe_link
URL to upgrade to FreightUtils Pro (50,000/month at ยฃ19/mo)
Installation
Claude Desktop / Claude Code (stdio)
Add to your MCP config (claude_desktop_config.json or .claude/settings.json):
If your MCP client supports remote servers, use the canonical URL:
code
https://www.freightutils.com/api/mcp
The older URL https://www.freightutils.com/api/mcp/mcp still works for backwards compatibility with existing clients.
No API key required to get started โ anonymous calls work out of the box (see Rate Limits below).
Authenticating with a Pro key
Anonymous usage caps at 25 requests/day per IP. If you have a free or Pro API key, set FREIGHTUTILS_API_KEY in the environment that runs the MCP server. The package reads it from process.env and attaches Authorization: Bearer <key> to every outbound /api/* call โ same key the remote https://www.freightutils.com/api/mcp transport already honors.
stdio config example with the env var wired through:
After adding FreightUtils to your MCP client config, fully quit and relaunch the client (Claude Desktop, Cursor, Cline). MCP servers are only loaded at client startup; editing the config in a running session does nothing until restart.
Then run the install diagnostic from a terminal:
sh
npx freightutils-mcp ping
You should see three ticks and All checks passed:
code
FreightUtils MCP Diagnostic
โโโโโโโโโโโโโโโโโโโโโโโโโโโ
package: freightutils-mcp@<installed version>
health: https://www.freightutils.com/api/mcp/health
[1/3] Backend health (https://www.freightutils.com/api/mcp/health)
โ status=ok mcp_version=<current> tools_registered=<current> (143ms)
[2/3] MCP handshake (in-process via InMemoryTransport)
โ server freightutils-mcp@<installed version> initialized; tools/list returned <n> tools
[3/3] End-to-end tool call (cbm_calculator l=120 w=80 h=100)
โ cbm_calculator โ total=0.96 mยณ (expected 0.96) (218ms)
All checks passed. Your FreightUtils MCP install is working.
If any check shows โ, see Troubleshooting below. Exit code is 0 on all-pass and 1 on any failure, so the command works in CI / health-check scripts too.
Troubleshooting
Symptom
Likely cause
Fix
Tools not appearing in the MCP client after editing the config
Client wasn't fully restarted
Quit and relaunch (Cmd+Q on macOS / right-click โ Quit on Windows tray). Closing the window is not enough.
npx freightutils-mcp ping check 1 fails with a network error
DNS, proxy, or the website is unreachable from your network
Check the status page at https://www.freightutils.com/status. If you're behind a corporate proxy, set HTTPS_PROXY. Override the host for ping with FREIGHTUTILS_API_URL=<base-url>.
npx freightutils-mcp ping check 2 fails
Broken local install (npx cache or stale Node version)
Re-install: rm -rf ~/.npm/_npx && npm install -g freightutils-mcp and rerun. Requires Node 18 or newer.
Tool calls return HTTP 429 / "rate_limited"
Anonymous IP cap of 25 requests/day exceeded
If you have a FreightUtils Pro API key, set FREIGHTUTILS_API_KEY in your environment before invoking the MCP. The package passes it through automatically on every outbound call. See https://www.freightutils.com/pricing if you need a key.
"Server failed to start" / spawn error in client logs
npx not on PATH, or Node older than 18
Install Node 18+. On macOS, an absolute path in the config ("command": "/opt/homebrew/bin/npx") avoids PATH issues for GUI-launched clients.
Specific tool returns isError: true
Bad input shape, or an unknown lookup key (UN number / HS code / AWB prefix not in the dataset)
The tool's error body names the offending field. Verify against the schema at https://www.freightutils.com/api-docs or call the corresponding playground endpoint to confirm the input shape.
The full diagnostic flow lives at the /api-docs#mcp-setup section on the website. The live backend status is callable from inside any MCP client at GET /api/mcp/health โ useful when you don't have shell access during a conversation.
"Calculate CBM for a box 120cm ร 80cm ร 100cm, 24 pieces"
"Look up UN 1203 in the ADR database"
"Check if 200L of petrol qualifies for ADR 1.1.3.6 exemption"
"Find the HS code for lithium batteries"
"What does FOB mean in shipping?"
"How many boxes of 40ร30ร25cm fit on a euro pallet?"
"Calculate loading metres for 26 euro pallets on an artic trailer"
"What's the UK import duty on laptops from China?"
Data Sources
ADR 2025 โ UNECE, ECE/TRANS/352, applicable 1 Jan 2025; given legal effect by EU
Directive 2008/68/EC (consolidated). Factual compilation, best-effort โ not legal advice,
not a regulatory authority.
HS 2022 โ UN Comtrade HS 2022 (Public Domain Dedication and Licence); the WCO
Harmonized System nomenclature is the authority.
Airlines โ the IATA / ICAO code registries. Authority only: this dataset carries no
per-record provenance, and no licence or "open data" claim is made for it.
UN/LOCODE 2025-1 โ UNECE official release artifact, coordinates strict-validated.
UK duty โ the live GOV.UK Trade Tariff API, pulled per request, so there is no local
copy that can drift.
ADEME Base Carbone v23.11), combined by the ISO 14083 / GLEC distance-based method.
Estimates, not audited reports.
Public provenance wording is maintained in the FreightUtils repository's
docs/DATA_PROVENANCE.md and copied here, not
written from memory โ so a source that is re-attributed there cannot keep being cited here.
A README that carries its own copy of the changelog is why three directories showed 2.4.0
as the latest release for three months after 2.4.0 had been superseded. One source now.
Other ways to use FreightUtils
FreightUtils ships across multiple distribution surfaces. Pick the one that fits how you work: