logistics-mcp
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@logistics-mcptrack shipment SBY-1003"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
logistics-mcp
Operations teams ask questions about shipments all day — "where is SBY-1042", "which route missed its SLA last month", "what would 12 kg to Makassar cost". The answers sit in a logistics system that an AI assistant cannot see. This MCP server exposes that system as nine tools, so Claude can answer from the actual data instead of from a screenshot the user pasted into the chat.
It runs out of the box against a bundled demo dataset (200 synthetic shipments across 6 cities over 3 months), so you can try every tool without credentials. Point it at your own backend by setting two environment variables.
The domain model comes from a production logistics platform I built (Next.js + Supabase, deployed on GCP). This repo contains the MCP server and a synthetic demo dataset, not the client application; no real customer names, rates, or operational data appear anywhere in it.
Architecture
Claude (Desktop / Code)
| MCP, stdio
v
logistics-mcp
tool handlers <- zod-validated inputs, row/byte caps, actionable errors
|
LogisticsSource <- one interface; handlers do not know which side is active
/ \
demo source rest source
fixtures/*.json LOGISTICS_API_URL + LOGISTICS_API_TOKEN (Bearer)The demo source reads the checked-in fixture JSON. The rest source expects the upstream
contract documented below. Writes are disabled unless ALLOW_WRITES=1; in demo mode an
update_shipment_status call mutates memory only and never touches the fixture files.
Related MCP server: Logistics AI MCP
Install
Claude Desktop (claude_desktop_config.json):
{
"mcpServers": {
"logistics": {
"command": "npx",
"args": ["-y", "logistics-mcp"]
}
}
}Claude Code:
claude mcp add logistics -- npx -y logistics-mcpBoth configurations need nothing else: no URL, no token, no clone. To connect your own
backend instead of the demo data, add LOGISTICS_API_URL and LOGISTICS_API_TOKEN to the
server's environment.
What a conversation looks like
Recorded against the demo dataset.
You: What's the status of shipment SBY-1003?
Claude calls track_shipment and gets the public timeline:
{
"spNumber": "SBY-1003",
"events": [
{ "at": "2026-07-11T05:35:01.991Z", "status": "READY", "location": "Surabaya", "description": "Shipment registered and waiting for pickup" },
{ "at": "2026-07-11T14:35:01.991Z", "status": "PICKED_UP", "location": "Surabaya", "description": "Picked up from sender" },
{ "at": "2026-07-12T11:35:01.991Z", "status": "IN_TRANSIT", "location": "Surabaya to Yogyakarta", "description": "On the way to the destination region" },
{ "at": "2026-07-13T02:35:01.991Z", "status": "AT_HUB", "location": "Yogyakarta hub", "description": "Arrived at destination sorting hub" },
{ "at": "2026-07-13T13:35:01.991Z", "status": "OUT_FOR_DELIVERY", "location": "Yogyakarta", "description": "With the courier for final delivery" },
{ "at": "2026-07-14T21:35:01.991Z", "status": "DELIVERED", "location": "Yogyakarta", "description": "Delivered to the recipient" }
]
}You: And what would 12 kg to Makassar cost on STANDARD?
quote_shipping_rate resolves the layered rate table and shows the math:
{
"freight": 174000,
"currency": "IDR",
"breakdown": {
"pricePerKg": 14500,
"minCharge": 25000,
"appliedRule": "destination_special",
"formula": "max(ceil(12 * 14500), 25000)"
},
"alternatives": [
{ "product": "ECONOMY", "freight": 68400 },
{ "product": "EXPRESS", "freight": 312000 }
]
}Other questions the demo data supports: "which route had the worst on-time rate in June"
(delivery_performance), "what's on the next load to Surabaya" (list_manifests →
get_manifest), "show everything Kirana Textiles shipped that's still in transit"
(search_shipments), "which customers still have unpaid invoices" (list_invoices).
Tools
Tool | What it answers |
| Find shipments by status, date range, route, or customer (limit default 20, max 100) |
| Full detail: items, extra charges, total amount, status history |
| Public tracking timeline, without internal ops notes |
| Price for route + weight + product, with the winning rate rule and the math |
| Outbound loads per region and date, with counts and total weight |
| Contents of one load |
| Per-route on-time rate, average transit days, exception counts for a period |
| Customer invoices by payment status or customer, with amount and due date |
| Write. Disabled unless |
Configuration
Variable | Default | Effect |
| (empty) | Empty: bundled demo dataset. Set: REST backend at this URL |
| (empty) | Bearer token for the REST backend. Required when the URL is set |
|
| Only the exact value |
|
| Per-call timeout for the data source |
|
| Responses above this are trimmed with a note on how to narrow the query |
If LOGISTICS_API_URL is set without a token, the server exits with a message naming the
missing variable. It does not fall back to demo data — a demo answer presented as
production data is worse than an error.
REST backend contract
The rest source expects these endpoints under LOGISTICS_API_URL, all with
Authorization: Bearer <LOGISTICS_API_TOKEN>:
GET /shipments?status&from&to&origin&destination&customer&limit&offset
GET /shipments/:spNumber
GET /shipments/:spNumber/tracking
GET /rates?origin&destination
GET /manifests?region&date&limit&offset
GET /manifests/:id
GET /invoices?status&customer&limit&offset
POST /shipments/:spNumber/status { "status": "...", "note": "..." }Response shapes match the TypeScript interfaces in src/sources/types.ts.
Security notes
Read-only by default. The single write tool stays off unless
ALLOW_WRITES=1, and when it is off the tool says how to enable it instead of failing with a generic error.No credentials in the repo and no credential defaults in code. The token comes from the environment and is sent only to
LOGISTICS_API_URL.Tool errors return sentences the model can act on ("no shipment matches SBY-9999; check the number or use search_shipments"), not stack traces or raw upstream responses.
List responses are capped in rows and in bytes, so one tool call cannot flood the client's context window.
stdio transport only; the server opens no network listener of its own.
Development
npm install
npm run build # tsc
npm test # vitest, runs against the demo dataset
npm run generate:fixtures # regenerate fixtures/data deterministicallyfixtures/generate.ts uses a fixed seed; regeneration must produce byte-identical output.
If it does not, the generator picked up nondeterminism — fix the generator, never hand-edit
the JSON. The demo-data review checklist in .claude/agents/demo-data-reviewer.md covers
the consistency rules the dataset must satisfy (chronology, rate math, cross-file
references).
The .claude/ setup is part of the repo's workflow, not decoration: a review subagent
(agents/demo-data-reviewer.md), a fixture-check skill (skills/check-fixtures/), and two
hooks wired in settings.json — hooks/no-stdout-log.sh keeps stray console.log out of
the stdio server, and hooks/no-null-bytes.sh blocks git commit when a staged text file
contains null bytes (a guard against UTF-16 output from PowerShell redirects, which once
published an empty README to npm).
Limitations
stdio only; no HTTP/SSE transport.
The demo dataset is synthetic and small by design (200 shipments). Aggregations like
delivery_performancefetch up to 1000 rows and stop there.No OAuth; the REST adapter authenticates with a static bearer token.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/Azzaraell/logistics-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server