Guides
SDKs and clients
Generate a typed client from the OpenAPI spec, or call the API directly with the snippets.
Official SDKs are on the way. Until they land, two paths get you a clean, typed integration today.
Generate a client from the OpenAPI spec
TrackingMCP, SchedulesMCP and LoadingMCP each publish an OpenAPI spec (linked from their reference overview). Point a generator at it and get a typed client in your language.
npx @openapitools/openapi-generator-cli generate \
-i https://trackingmcp.com/openapi.json \
-g typescript-fetch \
-o ./navo-tracking-client
Swap -g for python, go, java or any target the generator supports. The spec is the source of truth, so a regenerate keeps your client in step with the API.
Or call it directly
Every endpoint in the reference ships copy-paste samples in curl, JavaScript and Python. For most integrations a thin fetch or requests wrapper is all you need.
POST /v1/containers takes two required fields, identifier and identifier_type. Send one without the other, or send neither, and you get a 400 with VALIDATION_ERROR.
const NAVO_KEY = process.env.NAVO_KEY;
// identifierType is one of "container_id", "bill_of_lading" or "booking".
async function track(identifier, identifierType = "container_id") {
const res = await fetch("https://api.trackingmcp.com/v1/containers", {
method: "POST",
headers: {
"Authorization": `Bearer ${NAVO_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
identifier,
identifier_type: identifierType,
// carrier_code is optional. Omit it and we resolve the line from the prefix.
}),
});
if (!res.ok) throw new Error(`Navo ${res.status}`);
return res.json();
}
A successful add answers 201 with the record we opened:
{
"ok": true,
"data": {
"id": "8f1c2d4e-6a3b-4f52-9c70-11ab22cd33ef",
"identifier": "MEDU1234562",
"status": "in_transit",
"carrier_code": "MSCU",
"source": "direct_carrier"
}
}
idis the container UUID. Keep it: every other container endpoint is keyed on it.statusis the normalised status. A box we accepted but could not resolve on the first pass comes back asunknown, alongside awarningstring, and resolves within minutes as the re-poll runs.carrier_codeis the SCAC we resolved. An unresolved add carriesUNRESOLVED_CARRIERuntil a later poll names the line.sourcesays which path answered:direct_carrier,searatesorwarm_db.
Keep the key on your backend, read it from the environment, and branch on the status code. See errors and rate limits.
Let a model call the tools
If an assistant is doing the work, skip the client entirely and wire the MCP server. See the MCP quickstart.