adr_lookup
Search the ADR 2025 database for hazardous materials by UN number or substance name to get hazard class, packing group, labels, tunnel codes, and transport categories.
Instructions
Look up dangerous goods (hazmat) information from the ADR 2025 database.
ADR is the European agreement for international carriage of dangerous goods by road. This tool searches 2,939 entries covering all 9 hazard classes.
Use this tool when you need to:
Find the hazard class, packing group, and labels for a UN number
Search dangerous goods by name (e.g., "petrol", "lithium batteries")
Get tunnel restriction codes and transport categories
Check limited quantity allowances
Provide a UN number for exact lookup, or a search term for name-based search.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| un_number | No | UN number (e.g., "1203", "UN1203") | |
| search | No | Search by substance name (min 2 characters) | |
| hazard_class | No | Filter by hazard class (e.g., "3" for flammable liquids) |
Implementation Reference
- src/tools.ts:170-172 (handler)The handler function for 'adr_lookup' — calls the FreightUtils API endpoint 'adr' with un_number, search term, and optional hazard_class filter.
handler: async (args) => apiGet('adr', { un: args.un_number, q: args.search, class: args.hazard_class }), }; - src/tools.ts:162-166 (schema)Zod schema defining the input parameters: un_number (UN + 4 digits), search (min 2 chars), and hazard_class (optional string).
schema: z.object({ un_number: z.string().regex(/^(UN)?\d{4}$/i, 'UN number must be 4 digits, optionally prefixed with "UN" (e.g., "1203" or "UN1203")').optional().describe('UN number (e.g., "1203", "UN1203")'), search: z.string().min(2, 'Search term must be at least 2 characters').optional().describe('Search by substance name (min 2 characters)'), hazard_class: z.string().optional().describe('Filter by hazard class (e.g., "3" for flammable liquids)'), }).strict(), - src/tools.ts:717-717 (registration)The adrLookup ToolDef is exported in the ALL_TOOLS array, which is iterated over in server.ts to register the tool with the MCP server.
adrLookup, - src/server.ts:19-42 (registration)Server-side loop that registers every tool, including adr_lookup, with the MCP SDK server.
for (const tool of ALL_TOOLS) { server.tool( tool.name, tool.description, tool.schema.shape, tool.annotations, async (args: Record<string, unknown>) => { try { const result = await tool.handler(args); return { content: [ { type: 'text' as const, text: JSON.stringify(result, null, 2) }, ], }; } catch (err: unknown) { const message = err instanceof Error ? err.message : String(err); return { content: [{ type: 'text' as const, text: `Error: ${message}` }], isError: true, }; } }, ); } - src/api.ts:7-39 (helper)API helper function that builds the request URL and calls the FreightUtils API. The adr_lookup handler calls apiGet('adr', ...).
export async function apiGet(endpoint: string, params: Record<string, unknown>): Promise<unknown> { const url = new URL(`${BASE_URL}/${endpoint}`); for (const [k, v] of Object.entries(params)) { if (v === undefined || v === null || v === '') continue; url.searchParams.set(k, String(v)); } const res = await fetch(url.toString(), { headers: { 'Accept': 'application/json' }, }); if (!res.ok) { const body = await res.text(); throw new Error(`FreightUtils API error ${res.status}: ${body}`); } return res.json(); } export async function apiPost(endpoint: string, body: unknown): Promise<unknown> { const res = await fetch(`${BASE_URL}/${endpoint}`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' }, body: JSON.stringify(body), }); if (!res.ok) { const text = await res.text(); throw new Error(`FreightUtils API error ${res.status}: ${text}`); } return res.json(); }