PingPoint Freight MCP Server
Provides real-time freight tracking and load visibility for logistics and AI agents: create loads, get live GPS positions, trip stats, and confirm deliveries via geofenced statuses.
README
PingPoint — freight tracking MCP server and SDK
Real-time freight tracking and load visibility for logistics software and AI agents: an MCP server and a TypeScript SDK that give any agent live driver GPS position for a truckload shipment in US trucking — create a load over the API, the driver connects from an SMS link in about a minute, and from then on position, ETA, stop timeline and post-trip stats are one call away. No ELD provider integration, no corporate contract, no sales call.
| Package | npm | What it is |
|---|---|---|
@suverselabs/pingpoint-mcp |
npm i @suverselabs/pingpoint-mcp |
MCP server — 7 tools over stdio, for Claude and any MCP-capable agent |
@suverselabs/pingpoint-sdk |
npm i @suverselabs/pingpoint-sdk |
Typed API client — zero dependencies, typed errors, idempotent retries |
Full API documentation: https://pingpoint.suverse.io/docs · OpenAPI 3.1 spec: /docs/openapi.json
The problem
Most carriers in US trucking are one- or two-truck companies. They have no corporate telematics stack, no visibility contract, and no IT department — the truck is the company. When a broker needs to know where a load is, the only reliable instrument is a phone call to the driver.
That is why "AI track & trace" from most vendors today means a robot that calls a human and asks. The position data itself never becomes machine-readable — it lives in one driver's head, one call at a time. PingPoint makes the position itself available over an API: the driver installs one app from an SMS link, and from that moment any software — or any AI agent through MCP — reads live GPS instead of asking someone to dial.
How it works
1. A load is created over the API
POST /v1/agent/loads with the driver's phone and the stops. Required: driverPhone (E.164 — the driver link is texted to this number) and the pickups / deliveries arrays; every stop needs address, city, state, zip. Multi-stop loads are supported — several pickups and several deliveries, in array order.
The response carries the loadNumber (used in every later call), a public trackingLink for the customer, and the driver web/app links. Two safety nets against double-charging:
customerRefdoubles as a dedup key — re-sending the same reference returns the existing load (deduplicated: true) instead of creating a duplicate;- an
Idempotency-Keyheader makes retries after a network failure safe — the balance is debited and the load created at most once.
2. The driver connects from an SMS link
PingPoint texts the driver a link automatically. The link opens onboarding: install the app, tap through consent, done — about a minute of the driver's time, once. Under the hood the link carries a one-time load token which the app exchanges for a persistent device token, so the next load to the same phone number binds without any new setup.
3. Position flows in over two independent channels
- The driver's phone — background geolocation from the app.
- An ELD dongle on the truck's diagnostic port — streams vehicle data over Bluetooth to the app, which relays it. Tested with IOSiX and Pacific Track PT30 hardware. The dongle emits frames at 1 Hz; the app thins them before upload so the stored track stays dense enough for geofencing without drowning the pipeline.
The phone stays the gateway for both channels — the dongle talks to the app, not to the network. The point of two sources is that they fail differently: the dongle keeps positions coming for as long as the engine runs even when the phone's GPS can't get a fix or the OS has throttled background geolocation. Dongle frames also carry their own timestamps, taken from the frame itself rather than the moment of upload — so when a buffered backlog is flushed after an offline stretch, the recorded times are the real ones.
4. Statuses advance from geofences — never from a keyboard
Every pickup and delivery stop gets a geofence. Entering the pickup zone moves the load to AT_PICKUP, leaving it moves to IN_TRANSIT, entering the delivery zone to AT_DELIVERY — and DELIVERED is set when the truck departs the final delivery zone, not on arrival. The one shortcut is the explicit (free) delivery-confirm call (BOL in hand), which completes the load once the truck is at its delivery stop. Stop arrivedAt / departedAt timestamps come from the same geofence events.
External status writes are closed on purpose: PATCH …/status always answers 410 STATUS_DOOR_CLOSED. This is a data-integrity guarantee, not a missing feature — a status you read was never hand-set by anyone; there is recorded position behind it.
5. Reading it back
GET /v1/agent/loads/{loadNumber} returns the live state: status, the GPS track (up to the 500 most recent points), the stop timeline with arrival/departure timestamps, distance covered, dwell times, on-time flag and an ETA block computed from the stored route geometry and the latest position. After the trip, GET …/trip-stats returns an aggregated summary computed over every recorded ping. Webhooks can push load events to your endpoint as they happen (see the docs).
SMS link +---------------------+
(sent by ------> | Driver phone app |--- background GPS ---+
PingPoint) +---------------------+ |
v
+---------------------+ 1 Hz frames +--------------------+
| ELD dongle on the |---------------->| ingest (thinning) |
| diagnostic port, | via the app +--------------------+
| BLE (IOSiX, PT30) | |
+---------------------+ v
+-----------------+
| position store |
+-----------------+
| |
geofence engine <------+ |
| |
PLANNED -> AT_PICKUP -> IN_TRANSIT -> AT_DELIVERY -> DELIVERED
| |
v v
webhooks -> your endpoint GET /v1/agent/loads/{n} (position, ETA)
GET .../trip-stats (post-trip summary)
Quick start
Get a key
- Sign up at pingpoint.suverse.io (e-mail or Google/GitHub).
- In the cabinet open Integrations → Agent API and press Issue key.
- The
sup_agent_…key arrives by e-mail. PingPoint never stores the secret — if it's lost, re-issue a new one from the same page.
First call
curl -X POST https://api.suverse.io/v1/agent/loads \
-H "Authorization: Bearer sup_agent_…" \
-H "Content-Type: application/json" \
-d '{
"driverPhone": "+15551234567",
"pickups": [{ "address": "6492 Tower Lane", "city": "Claremore", "state": "OK", "zip": "74017" }],
"deliveries": [{ "address": "6499 Caldwell Park Dr", "city": "Charlotte", "state": "NC", "zip": "28269" }],
"customerRef": "PO-483920"
}'
{
"success": true,
"loadId": "3b9f6a2e-1c47-4d8a-9e02-7f5b1c8d4a63",
"loadNumber": "LD-2026-042317",
"trackingLink": "https://pingpoint.suverse.io/track/trk_…",
"driverWebLink": "https://pingpoint.suverse.io/driver/drv_…",
"driverAppLink": "pingpoint://driver/drv_…",
"driverResolution": "none"
}
The driver link is already on its way to +15551234567 by SMS. From here, GET /v1/agent/loads/LD-2026-042317 reads the live position.
Connect the MCP server
Claude Code, one line:
claude mcp add pingpoint --env PINGPOINT_AGENT_KEY=sup_agent_… -- npx -y @suverselabs/pingpoint-mcp
Claude Desktop (claude_desktop_config.json) or any MCP-capable agent:
{
"mcpServers": {
"pingpoint": {
"command": "npx",
"args": ["-y", "@suverselabs/pingpoint-mcp"],
"env": {
"PINGPOINT_AGENT_KEY": "sup_agent_…"
}
}
}
}
Restart the agent and the tools appear.
MCP tools
Detailed per-tool reference with full request/response examples: docs/tools/.
| Tool | What it does | Parameters | Returns | Price |
|---|---|---|---|---|
create_load |
Creates a freight load; PingPoint texts the driver link to driverPhone |
driverPhone, pickups[], deliveries[] (required); shipperName, carrierName, equipmentType, customerRef, rate, miles, weight, truckNumber, idempotencyKey (optional) |
loadNumber, public trackingLink, driver web/app links, driverResolution, dedup flag |
$0.65 |
get_load_position |
Live state of a load | loadNumber |
status, GPS track (last 500 points), stops with arrive/depart timestamps, distance, on-time flag, dwell times, ETA block | $0.02 |
get_trip_stats |
Aggregated summary of the whole GPS trip (meant for a DELIVERED load; mid-trip returns the trip so far) | loadNumber |
stats: distance, duration, avg/max speed, hard accel/brake counts, city/highway/parked/night shares, GPS coverage, first/last ping |
$0.02 |
update_load_status |
Intentionally closed — statuses are GPS-verified | loadNumber, status |
always HTTP 410 STATUS_DOOR_CLOSED |
free |
confirm_delivery |
BOL received → load at its delivery stop flips to DELIVERED (idempotent) | loadNumber, bolReceivedAt (optional, ISO 8601) |
{ ok, oldStatus, newStatus: "DELIVERED" } |
free |
get_pricing |
Current USD price list | — | { currency, prices } |
free |
get_balance |
Prepaid balance | — | { currency, balanceUsd } |
free |
Tool descriptions are written for the calling model: each one states what it costs, when to use it and when not to (e.g. get_load_position answers "where is the truck now", get_trip_stats answers "how did the finished trip go", and both warn against polling in a loop because every call is billed).
SDK
npm install @suverselabs/pingpoint-sdk
import { PingPointAgent, InsufficientFundsError, DeliveryNotReadyError } from "@suverselabs/pingpoint-sdk";
const pp = new PingPointAgent({ apiKey: process.env.PINGPOINT_AGENT_KEY! });
// $0.65 — driver gets the app link by SMS
const load = await pp.createLoad(
{
driverPhone: "+15551234567",
pickups: [{ address: "6492 Tower Lane", city: "Claremore", state: "OK", zip: "74017" }],
deliveries: [{ address: "6499 Caldwell Park Dr", city: "Charlotte", state: "NC", zip: "28269" }],
customerRef: "PO-483920",
},
{ idempotencyKey: "PO-483920" },
);
const pos = await pp.getPosition(load.loadNumber); // $0.02
const trip = await pp.getTripStats(load.loadNumber); // $0.02, best after DELIVERED
await pp.confirmDelivery(load.loadNumber, { bolReceivedAt: new Date() }); // free
Methods: createLoad(input, { idempotencyKey? }), getPosition(loadNumber), getTripStats(loadNumber), updateStatus(loadNumber, status) (documented to throw the intentional 410), confirmDelivery(loadNumber, { bolReceivedAt? }), getPricing(), getBalance(). Full reference: docs/sdk.md.
Every non-2xx answer throws a typed subclass of PingPointAgentError carrying .status and the raw .body:
try {
await pp.createLoad(input);
} catch (err) {
if (err instanceof InsufficientFundsError) {
console.log(`balance $${err.balanceUsd}, need $${err.priceUsd} — nothing was charged`);
} else if (err instanceof DeliveryNotReadyError) {
// driver hasn't arrived yet — do NOT retry; the load completes automatically when the truck departs the delivery zone
}
}
Node ≥ 18 (uses global fetch), ESM + CJS, zero runtime dependencies.
Data model
Position (get_load_position / getPosition)
| Field | Unit / format | Meaning |
|---|---|---|
status |
enum | PLANNED, AT_PICKUP, IN_TRANSIT, AT_DELIVERY, DELIVERED, CANCELLED — advanced automatically from GPS and geofence events |
gpsTrack[] |
— | Up to the 500 most recent points, oldest first |
gpsTrack[].lat / lng |
degrees | Position fix |
gpsTrack[].speed |
mph, 1 decimal | Ground speed; null when the fix carries none |
gpsTrack[].heading |
degrees 0–359, 0 = north | null when unknown |
gpsTrack[].ts |
ISO 8601 UTC | Fix timestamp |
distanceMiles |
miles | Haversine over the full track (not just the 500 returned points); null until ≥ 2 pings |
stops[].arrivedAt / departedAt |
ISO 8601 UTC | Set by geofence arrival/departure |
stops[].windowFrom / windowTo |
ISO 8601 UTC | Planned windows, null when not set |
onTime |
boolean | Delivered within the delivery window (15 min grace); null until delivered or without a window |
delayMinutes, pickupDwellMinutes, deliveryDwellMinutes |
minutes | null when not yet known |
pingCount |
count | Total pings recorded for the load |
eta |
object | Next stop, distance to it (mi), drive time (h), moving flag, ETA window; fail-soft — degrades to a reason-only object when there is not enough data |
Trip stats (get_trip_stats / getTripStats)
| Field | Unit | Meaning |
|---|---|---|
dataPoints |
count | GPS pings recorded for the load |
durationSeconds |
s | lastAt − firstAt |
estimatedDistanceMiles |
miles | Haversine over the full recorded track |
avgSpeedMph |
mph | Over the whole span, stops included |
maxSpeedMph |
mph | Maximum recorded ground speed |
hardAccelCount |
count | Speed gain > +15 mph/min while moving > 20 mph |
hardBrakeCount |
count | Speed drop < −20 mph/min while moving > 20 mph |
cityMilesPct |
% 0–100 | Share of miles at 5–45 mph |
highwayMilesPct |
% 0–100 | Share of miles above 45 mph |
parkedTimePct |
% 0–100 | Share of pings at ≤ 5 mph |
nightPct |
% 0–100 | Share of pings between 23:00–07:00 UTC |
coveragePct |
% ≤ 100 | Pings vs. a one-per-minute expectation over the span |
firstAt / lastAt |
ISO 8601 UTC | First/last recorded ping; null when no pings |
Error codes
| Code | Meaning |
|---|---|
400 MISSING_FIELDS |
Required fields absent — the body lists them in fields[] (dotted paths, e.g. pickups.0.zip). Also 400 INVALID_DRIVER_PHONE when the phone is not E.164. |
401 |
Missing or invalid key. |
402 INSUFFICIENT_FUNDS |
Prepaid balance can't cover the operation. Nothing was charged and nothing was created. Body carries balanceUsd, priceUsd, billingUrl. |
403 |
The load belongs to another account. |
404 |
No such load. |
410 STATUS_DOOR_CLOSED |
Answer to any external status write. Not an outage — by design. Don't retry. |
422 UNKNOWN_BROKER |
The key's account is not registered on PingPoint. |
422 + reason: bol_received_before_geofence_arrive |
Delivery confirm before the truck reached the delivery stop. Don't retry — once the truck is at the stop the confirm succeeds, and without it the load completes automatically on departure from the delivery zone. |
503 BILLING_UNAVAILABLE |
Billing backend temporarily unreachable — nothing was charged, retry later. |
Billing
Prepaid balance, per-call pricing, no subscription. Details: docs/billing.md.
| Operation | Price |
|---|---|
| Create a load | $0.65 |
| Read load position | $0.02 per request |
| Trip summary stats | $0.02 per request |
| Delivery confirm, status endpoint, pricing, balance | free |
- Top up in the cabinet under Billing. Free operations work at zero balance.
- A
402means the call was rejected before anything happened: nothing created, nothing charged. createLoadretries are safe with the sameIdempotency-Key— the debit happens at most once;customerRefdeduplicates at the business level.- Prices are served live by
GET /v1/agent/pricing— treat that as the source of truth, never hardcode them.
What this is not
- Not a certified ELD. PingPoint reads GPS (and, through the dongle, engine-bus data) for visibility. It is not an FMCSA-registered ELD and does not produce HOS/RODS compliance records.
- Not carrier vetting. A live position tells you where the truck is, not whether the carrier is safe, insured or real. Keep whatever onboarding checks you run today.
- The driver has to install the app. One SMS link, one install, about a minute — but it is a real step that requires the driver's cooperation. A load with no connected phone and no dongle produces no positions.
How this compares
Enterprise visibility platforms assume the carrier already has telematics and the broker already has a contract; call-based tracking vendors put a phone call (human or robotic) in the loop for every check. PingPoint's trade is different: one driver-side install in exchange for a per-call API with published prices and no minimums. A factual, cell-by-cell comparison with both groups — key issuance, public pricing, API surface, MCP/SDK availability — is maintained at pingpoint.suverse.io/compare.
Links
- API documentation: https://pingpoint.suverse.io/docs
- OpenAPI 3.1 spec: https://pingpoint.suverse.io/docs/openapi.json
- Comparison with alternatives: https://pingpoint.suverse.io/compare
- MCP server on npm: https://www.npmjs.com/package/@suverselabs/pingpoint-mcp
- SDK on npm: https://www.npmjs.com/package/@suverselabs/pingpoint-sdk
- In-repo docs: architecture · billing · SDK reference · MCP tools
- Contact: info@suverse.io
License
MIT © 2026 Sudzik Group Inc.
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.
E2B
Using MCP to run code via e2b.