CargoMind MCP Server
Provides routing and geocoding capabilities using Google Maps Routes v2 and Geocoding APIs, used for shipment lane mapping, route planning, and disruption impact assessment.
Integrates with OpenAI GPT models (e.g., GPT-6.1 Sol, GPT-6 Luna, GPT-5 Mini) as a multi-model provider for conversation, planning, and fallback, enabling cross-vendor failover.
Provides an alternative mapping and routing fallback to Google Maps, used when Google Maps API is unavailable, ensuring continued geocoding and route calculations.
Click on "Deploy 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., "@CargoMind MCP ServerTrack shipment SHP-48291 and any active exceptions."
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.
CargoMind
A self-healing, multi-model, multi-agent logistics control tower.
Built on Google ADK, OpenAI GPT-6.1 Sol / GPT-6 Luna, Google Maps and MCP. Ask it about any shipment, lane, truck or SKU in an India-wide 3PL network. It plans, checks its own work and keeps answering when models, APIs or servers fail. The previous Gemini/Anthropic chain remains available with CARGOMIND_PROVIDER=multi.
▶ Open the live demo · Run it locally in 60 s · Criteria → proof · See it in action · Submission overview
Quickstart · Criteria map · Architecture · Demo script · Self-healing · Feedback loops · Deploy

23 | 3 vendors | 11 + 2 | 18 / 18 | 0 |
Google ADK agents using | Gemini → Claude / GPT → offline engine, failover per request | MCP tools + resources in our own server | eval scenarios pass, also under 30% injected chaos | API keys needed to run it |
Self-healing, seen live. One real request from our live runs, straight from the healing journal:
gemini-3.8-flash→ 429 RESOURCE_EXHAUSTED ·gemini-3.6-flash→ 429 ·anthropic/claude-sonnet-5-5→ error · served byopenai/gpt-5-mini— recovered. The operator just got their answer. Across those runs the journal recorded 19 automatic cross-vendor model recoveries.
Judge fast path: 90-second demo · criterion-by-criterion evidence · reproducible eval report. Verified: 106 tests pass, 18/18 offline scenarios succeed, routing F1 0.974. The timed demo uses the offline engine; live provider usage is visible in the trace.
Resilience evidence: 30% chaos eval also completed 18/18 scenarios, with 14 injected faults, 12 retries and 12 recorded recoveries. Both eval runs use the offline model and in-process MCP; CI separately exercises stdio MCP and Docker.
Simulation readiness
Open /simulation on the running server for a configurable logistics graph, explicit multi-agent handoffs, independently verified route decisions, and a forged-output rejection demo. The interface accepts operational IDs and numeric constraints; personal/contact fields are rejected. Proposals remain read-only.
Run uv run cargomind simulate --input scenario.json or POST a scenario to /api/simulation/run. See simulation schema and protocol, evaluation method, and raw-count benchmark report. The protocol is custom JSON handoff 1.0 over JSON-RPC 2.0; existing ADK agents invoke the same optimizer. Deterministic routing scores are distinct from LLM hallucination measurements.
Related MCP server: Logistics AI MCP
Contents
More depth: docs/ARCHITECTURE.md (sequence diagrams), docs/JUDGING.md (criteria checklist with file links), docs/DEMO_SCRIPT.md (3-minute live demo run-sheet).
See it in action
Disruption Autopilot: one sentence starts a multi-agent incident response. "Cyclone alert in Chennai, severity high: run disruption autopilot." The map draws the impact zone around Chennai and lights up every exposed lane. Then impact_assessor hands off to a ParallelAgent (reroute planner + notice drafter), and autopilot_commander writes the incident action plan for the operator to approve. In this capture the journal on the right shows Gemini hitting its quota and the run continuing on the next model.

Multimodal proof-of-delivery inspection that knows when not to guess. Attach a delivery photo and Gemini vision returns damage_detected, severity, findings and the next action. In this capture Gemini vision was over quota, so the local Pillow fallback answered instead: it marked the result degraded, explained why and asked for human review rather than inventing a verdict.
Watchtower acts before you ask. It scans SLAs, exceptions, stock, fleet and hub weather every 60 s. Each alert is a one-click question to the agent; weather alerts launch the autopilot.
The 30-second pitch
The problem. A logistics control tower runs on a dozen screens: a TMS for shipments, a WMS for stock, maps for routes, weather for risk, spreadsheets for dispatch, WhatsApp for customers. Most AI assistants for this job stop working the moment an API rate-limits, a model returns a 429 or a backend crashes. In operations that is the moment you need them.
CargoMind puts the whole control tower behind one conversation:
One concierge, many specialists. A conversational Gemini agent sends each request to 8 specialist agents: tracking, routes and risk, inventory, dispatch, customer comms, photo inspection, the ops briefing and the Disruption Autopilot. The graph has 23 ADK agents in total and uses every ADK workflow pattern:
LlmAgent+AgentTool,SequentialAgent,ParallelAgentandLoopAgent.Multi-model by design. Conversation, planning and vision tiers prefer Gemini models. The independent dispatch critic prefers Claude or GPT. The trace records which provider actually ran after any fallback. A deterministic offline rule-engine is the last link of every model chain.
It checks its own work. The dispatch planner and an independent critic run in a feedback loop. The critic checks truck capacity, driver hours, cold-chain and hazmat handling, SLA and weather. The planner revises until the plan is valid. Nothing is written to the database until you say "commit the plan".
It acts before you ask. The Watchtower scans the network every 60 s for SLA breach risk, exceptions, low stock, fleet problems and hub weather, and turns each alert into a one-click question. For a cyclone, flood, strike or closure, the Disruption Autopilot assesses the impact, plans reroutes and drafts customer notices in parallel, then hands the operator an incident action plan to approve.
It learns from the operator. Thumbs up or down, comments and "remember: always..." are turned into lessons. Those lessons are added to the agent's instructions on every turn.
It heals itself. The system has five layers of self-healing:
model failover across vendors
tool-argument repair, retries and circuit breakers
API fallbacks: Google Maps → OpenStreetMap → offline math
MCP-server failover
a Chaos Monkey slider so you can break things live and watch it recover
Every fault and recovery is written to a live healing journal.
Runs with zero keys.
git clone→uv sync→uv run cargomind webgives you a working system with no API keys at all. Add keys to switch on Gemini, Claude/OpenAI and Google Maps.
How CargoMind meets the judging criteria
Criterion | How CargoMind meets it | Where to look | Verify in under a minute |
Tool set: Agent SDK | Built on Google ADK 2.12. It uses |
| |
Tool set: Google products | Gemini in 4 roles (fast, pro, backup, multimodal vision). Google Maps Routes API v2 and Geocoding API. Cloud Run, Cloud Build and Secret Manager for deployment. The ADK Dev UI. Gemini CLI as an MCP client |
|
|
"No half-baked information: A–Z instructions" | This README covers a zero-key quickstart, setup for each OS, every API key step by step, every env var and command, the dashboard, ADK UI, MCP, Docker, Cloud Run and troubleshooting. | this file, | Follow Quickstart on a clean machine |
Multi-model agents | 4 model tiers across Gemini + Claude/OpenAI + an offline engine. When a Claude or OpenAI key is set, the critic deliberately runs on a different vendor from the planner. Images go to Gemini multimodal. Each answer is tagged with the model that served it ( |
| Dashboard trace and CLI show |
Conversational agents | The |
|
|
API calls | Google Routes v2 ( | Ask "Any weather risk on Mumbai → Pune today?" | |
MCP integration | CargoMind ships its own MCP server ( |
|
|
Feedback loop | (1) Planner and critic run in a | "Plan today's dispatch from Mumbai", then a thumbs-down with a comment | |
Self-healing agents | 5 layers: a resilient model chain with rollback, the | Set the dashboard Chaos slider to 30% and keep chatting | |
Submission: GitHub repo + README | MIT-licensed repo with CI (lint, tests, offline end-to-end demo under chaos, Docker build), a Dockerfile and a one-command Cloud Run deploy | CI badge at the top |
A per-criterion checklist with file and symbol pointers is in docs/JUDGING.md.
Architecture
System view
flowchart TB
subgraph IF["Interfaces"]
WEB["Mission-control dashboard<br/>FastAPI + SSE + Leaflet"]
CLI["CLI<br/>chat / demo / doctor<br/>autopilot / watchtower / eval"]
ADKUI["ADK Dev UI<br/>adk web src"]
EXT["External MCP clients<br/>Claude Desktop / Claude Code / Gemini CLI"]
end
subgraph RT["Google ADK runtime"]
RUN["Runner + session service<br/>stream_chat event stream"]
PLUG["SelfHealingPlugin<br/>arg repair / retries / breakers / reflect"]
CON["cargomind_concierge<br/>conversational orchestrator"]
SPEC["8 specialist agents<br/>exposed as AgentTools"]
WT["Watchtower<br/>background scan every 60 s"]
end
subgraph MODELS["ResilientLlm chain - one per agent"]
G["Gemini tier model"] --> GB["Gemini backup"] --> V2["Claude or GPT<br/>via LiteLLM"] --> OFF["Offline rule-engine"]
end
subgraph TOOLS["Tools"]
MCPT["ResilientMcpToolset<br/>MCP client with in-process failover"]
GEO["geo: routes, multi-stop, geocode"]
WX["weather: risk, route disruptions"]
PLAN["planning: quotes, ETA,<br/>propose / validate / commit plan"]
VIS["vision: proof-of-delivery photo"]
COMMS["comms: draft + simulated send"]
FB["feedback: remember_operator_feedback"]
end
MCPS["cargomind-logistics MCP server<br/>11 tools + 2 resources, stdio"]
DB[("SQLite<br/>shipments / fleet / stock / POs / outbox<br/>healing_events / feedback / preferences")]
WEB & CLI & ADKUI --> RUN --> CON --> SPEC
PLUG -.-|"wraps every tool and model call"| RUN
CON -.- MODELS
SPEC -.- MODELS
SPEC --> MCPT & GEO & WX & PLAN & VIS & COMMS
CON --> FB & PLAN
MCPT -- "stdio JSON-RPC" --> MCPS --> DB
EXT -- "stdio JSON-RPC" --> MCPS
PLAN & COMMS & FB --> DB
WEB --> WT --> DB
GEO --> GM["Google Routes v2 + Geocoding"] -.->|fallback| OSM["OSRM / Nominatim"] -.->|fallback| HAV["Haversine + gazetteer"]
WX --> OM["Open-Meteo"] -.->|fallback| SEAS["Seasonal heuristic"]
VIS --> GV["Gemini multimodal"] -.->|fallback| PIL["Pillow heuristic"]Agent graph
flowchart LR
U(["Operator"]) --> CON["cargomind_concierge<br/>LlmAgent - fast tier"]
CON -->|AgentTool| TRK["tracking_agent"]
CON -->|AgentTool| RRK["route_risk_agent"]
CON -->|AgentTool| INV["inventory_agent"]
CON -->|AgentTool| DP
CON -->|AgentTool| COM["comms_agent"]
CON -->|AgentTool| VI["vision_inspector<br/>vision tier"]
CON -->|AgentTool| OB
CON -->|AgentTool| AP
CON -->|tool| CMT["commit_dispatch_plan"]
CON -->|tool| REM["remember_operator_feedback"]
subgraph DP["dispatch_pipeline - SequentialAgent"]
direction TB
subgraph LOOP["plan_critique_loop - LoopAgent, max 4"]
PL["dispatch_planner<br/>pro tier"] --> CR["dispatch_critic<br/>critic tier = other vendor"]
CR -->|"issues -> revise"| PL
end
LOOP -->|"exit_loop when valid"| REP["dispatch_reporter"]
end
subgraph OB["ops_briefing - SequentialAgent"]
direction TB
subgraph FAN["signal_fanout - ParallelAgent"]
K["kpi_watch"]
R["risk_watch"]
S["stock_watch"]
end
FAN -->|"output_key state"| BW["briefing_writer"]
end
subgraph AP["disruption_autopilot - SequentialAgent"]
direction TB
IA["impact_assessor"] --> MF
subgraph MF["mitigation_fanout - ParallelAgent"]
RP["reroute_planner<br/>pro tier"]
ND["notice_drafter<br/>drafts only"]
end
MF -->|"output_key state"| AC["autopilot_commander<br/>incident action plan"]
endModel chain (one per agent, built by build_model(tier))
Tier | Used by | Chain, tried in order (links without a key are left out) |
| concierge, tracking, route/risk, inventory, comms, reporter, watchers, briefing writer, impact assessor, notice drafter, autopilot commander |
|
| dispatch planner, autopilot reroute planner |
|
| dispatch critic | Claude or GPT first (independent vendor) → |
| vision inspector |
|
The second vendor is Claude (anthropic/claude-sonnet-5-5) when ANTHROPIC_API_KEY is set. Otherwise it is GPT (openai/gpt-5-mini) when OPENAI_API_KEY is set. Both run through LiteLLM. Every model id can be overridden: see Configuration reference.
Sequence diagrams for a dispatch request and a self-healing fallback are in docs/ARCHITECTURE.md.
Feature tour
Agent | ADK pattern | Model tier | What it does | Tools |
|
| fast | Conversational front door. Understands the goal, calls one or more specialists in a single turn, asks clarifying questions and applies learned lessons | 8 specialist AgentTools, |
|
| fast | Status, location, history, ETA and SLA risk. Updates status only when asked | MCP: |
|
| fast | Road distance and time, multi-stop optimisation, weather and disruption risk, carrier quotes |
|
|
| fast | Stock levels, low-stock alerts, reorders (POs only when asked), warehouse info | MCP: |
|
| pro + critic + fast | Assigns pending shipments to own-fleet trucks. An independent critic checks capacity, driver hours, cold chain, hazmat, SLA, weather and duplicates. The planner revises (weather deferrals, driver swaps, team drivers, carrier hand-offs, corridor splits) until the plan is valid, then a report is written |
|
|
| fast | Empathetic, specific delay or delivery notices (email, SMS, WhatsApp). Sends only after approval, to a simulated outbox |
|
|
| vision | Proof-of-delivery photo inspection: damage, severity, findings, recommended action |
|
|
| fast | Morning briefing: KPIs, weather at 6 hubs and low stock are gathered in parallel, then written up as Headline, Risks and Actions | MCP |
|
| fast + pro | City-level disruption (cyclone, flood, strike, bandh, closure, landslide): finds exposed shipments, vehicles and warehouses, proposes reroutes/holds via an alternate hub, drafts customer notices (never sends) and writes an incident action plan. Nothing executes until the operator approves |
|
The seeded network. On first run CargoMind creates data/cargomind.db with a deterministic India-wide network. It contains 25 shipments (SHP-1001…SHP-1025, with real-world problems such as checkpost holds, monsoon delays, crushed cartons and hazmat), 5 warehouses (WH-BOM, WH-DEL, WH-BLR, WH-MAA, WH-HYD), 20 SKUs (some below their reorder point), 10 trucks (TRK-101…TRK-110, including a cold-chain reefer), 5 carriers (CR-01…CR-05) and a 20-city gazetteer. The gazetteer knows aliases such as Bangalore, Bombay, Madras and Gurgaon, and IATA-style codes such as BLR and BOM.
Quickstart
Works on Windows, macOS and Linux with zero API keys. You need Git and uv. uv installs Python 3.12 for you if you don't have it.
git clone https://github.com/Anandb71/cargomind
cd cargomind
uv sync
cp .env.example .env # Windows: copy .env.example .env
uv run cargomind web # open http://localhost:8080Then try uv run cargomind doctor (self-check), uv run cargomind demo (scripted 8-step scenario) or uv run cargomind chat (terminal chat).
With no keys, every answer comes from the offline rule-engine and the free or offline API fallbacks. The answers are structured and correct but templated. Add a free Gemini key to
.env(2 minutes) to get the full multi-model experience.
Full setup (Windows, macOS, Linux)
Prerequisites
Need | Why | Install |
Git | clone the repo | https://git-scm.com/downloads (or use GitHub's Code → Download ZIP) |
uv | Python + dependency manager (reads | see below |
Internet on first run | download dependencies; live APIs are optional | – |
(optional) Docker | container run | |
(optional) Google Cloud SDK | Cloud Run deploy | |
(optional) Node.js 18+ | MCP Inspector only |
Windows 10/11 (PowerShell)
# 1. Install uv, then CLOSE and REOPEN the terminal so `uv` is on PATH
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
# 2. Get the code (two separate lines: Windows PowerShell 5.1 has no `&&`)
git clone https://github.com/Anandb71/cargomind
cd cargomind
# 3. Install Python 3.12 + all dependencies into .venv
uv sync
# 4. Create your settings file (all keys optional)
copy .env.example .env
notepad .env
# 5. Check, then run
uv run cargomind doctor
uv run cargomind webOpen http://localhost:8080. If you hit "path too long" errors or garbled characters, see Troubleshooting.
macOS
curl -LsSf https://astral.sh/uv/install.sh | sh # or: brew install uv
exec $SHELL -l # reload PATH
git clone https://github.com/Anandb71/cargomind && cd cargomind
uv sync
cp .env.example .env && open -e .env
uv run cargomind doctor
uv run cargomind web # http://localhost:8080Linux
curl -LsSf https://astral.sh/uv/install.sh | sh
source "$HOME/.local/bin/env" 2>/dev/null || export PATH="$HOME/.local/bin:$PATH"
git clone https://github.com/Anandb71/cargomind && cd cargomind
uv sync
cp .env.example .env && ${EDITOR:-nano} .env
uv run cargomind doctor
uv run cargomind web # http://localhost:8080Verify the install
uv run cargomind doctor prints which providers are live, the configured model ids, live KPIs from the seeded database, and a smoke-test answer to "Where is SHP-1003?". The first line tells you the mode:
CargoMind | live: none | offline rule-engine fallback: on <- zero keys
CargoMind | live: gemini, claude, google_maps | offline rule-engine fallback: on <- keys picked upGetting the API keys
Every key is optional. Put keys in .env at the repo root. Empty values and placeholders that start with PASTE_, YOUR_ or < are ignored. Environment variables already set in your shell take precedence over .env. After changing .env, restart the command and re-run uv run cargomind doctor.
What each key unlocks
You set | Conversation and planning | Dispatch critic | Routes and geocoding | Weather | Photo inspection |
(nothing) | offline rule-engine | offline rule-engine | OSRM / Nominatim (free, no key) → haversine | Open-Meteo (free, no key) → seasonal heuristic | Pillow heuristic |
| Gemini fast / pro + backup | Gemini Pro | same as above | same | Gemini multimodal |
+ | + cross-vendor failover | Claude / GPT (independent vendor) | same | same | same |
+ | – | – | Google Routes API v2 + Geocoding | same | same |
| forces offline everywhere (no network at all) | offline | gazetteer + haversine | seasonal heuristic | Pillow heuristic |
1. Gemini API key (the brain)
Open https://aistudio.google.com/apikey and sign in with a Google account.
Click Create API key. Pick an existing Google Cloud project or let AI Studio create one.
Copy the key and paste it into
.env:GOOGLE_API_KEY=AIza...your-key...Run
uv run cargomind doctor. The first line should now includegemini.
The free tier has per-minute limits. When you hit one, Gemini returns HTTP 429. CargoMind retries, then fails over to the backup Gemini model, then to the second vendor, then to the offline engine, automatically (see Self-healing).
GOOGLE_GENAI_USE_VERTEXAI=true
GOOGLE_CLOUD_PROJECT=your-project-id
GOOGLE_CLOUD_LOCATION=us-central1Then authenticate once with gcloud auth application-default login. Enable the Vertex AI API on the project, and check that the model ids you configure are available in that location.
2. Google Maps API key (Routes API + Geocoding API)
Open https://console.cloud.google.com/ and select (or create) a project. Google Maps Platform requires a billing account on the project. It includes a monthly free usage allowance; check current pricing on the Maps Platform site.
Go to APIs & Services → Library. Search for Routes API and click Enable. Then search for Geocoding API and click Enable. CargoMind calls the Routes API v2 endpoint
routes.googleapis.com/directions/v2:computeRoutes, not the legacy Directions API.Open https://console.cloud.google.com/google/maps-apis/credentials and choose Create credentials → API key.
Recommended: click the key, open API restrictions, choose Restrict key and select Routes API and Geocoding API.
Paste it into
.env:GOOGLE_MAPS_API_KEY=AIza...your-maps-key...Run
uv run cargomind doctor. The first line should now includegoogle_maps. Route answers now showsource: google_routes. Before this they showedosrmorhaversinewithdegraded: true.
3. Second-vendor model: Claude or OpenAI (pick one)
Anthropic Claude (preferred when both are set):
Open https://console.anthropic.com/settings/keys. Add credits under Billing if the account is new.
Click Create Key, name it
cargomindand copy it.Add
ANTHROPIC_API_KEY=sk-ant-...to.env.
OpenAI:
Open https://platform.openai.com/api-keys. The account needs billing or credits.
Click Create new secret key and copy it.
Add
OPENAI_API_KEY=sk-...to.env.
The second vendor runs the dispatch critic first, so the plan is reviewed by a different model family from the one that wrote it. It is also the cross-vendor failover link for every other agent. If both keys are set, Claude is used.
Configuration reference
Every setting is an environment variable, read in src/cargomind/config.py. Put them in .env or export them in your shell. Shell values win.
Variable | Default | Purpose |
| (empty) | Gemini API key. Enables all Gemini tiers and Gemini vision |
|
|
|
| (empty) | Google Routes API v2 + Geocoding API |
| (empty) | Claude as the second vendor (critic + failover) |
| (empty) | GPT as the second vendor if no Anthropic key is set |
|
| Fast conversational / routing model |
|
| Deep-reasoning model for the planner (and critic fallback) |
|
| Same-vendor backup, tried before switching vendors |
| value of | Multimodal model for proof-of-delivery photos |
|
| LiteLLM model id for Claude |
|
| LiteLLM model id for OpenAI |
|
|
|
|
|
|
|
| Chaos Monkey fault-injection rate, |
|
| Retries per failed tool call (exponential backoff 0.3 s, 0.6 s, …) |
|
| Consecutive failures that open a circuit breaker |
|
| Seconds a breaker stays open before a half-open trial |
|
| Seconds per external HTTP call before falling back |
|
| Where the SQLite DB and uploaded photos live |
|
| SQLite database file |
|
|
|
|
| Dashboard port (Cloud Run sets it automatically) |
|
| Dashboard bind address |
|
| Uvicorn log level for the dashboard |
| set to | UTF-8 I/O for LiteLLM and child processes on Windows |
CLI reference
All commands run from the repo root with uv run …. They are installed as console scripts by uv sync.
Command | What it does |
| Shows live providers and model ids, prints KPIs from the DB and runs a one-question smoke test |
| Starts the mission-control dashboard and API at http://localhost:8080 (API docs at |
| Interactive multi-turn chat in the terminal. Shows tool calls ( |
| Runs the scripted 8-step scenario from Demo script in one session, then prints self-healing stats |
| Same, with 30% of tool and model calls failing on the first try, to show self-healing |
| Runs the |
| Re-seeds the demo database (shipments, fleet, stock, POs, outbox) |
| Runs the Disruption Autopilot steps directly (impact → reroutes → notice drafts) and prints the actions. |
| Same, but through the full multi-agent concierge ( |
| One Watchtower scan: prints every active alert with severity, detail and the suggested question |
| Runs the 18-scenario eval harness and writes the report. All flags pass through to |
| Google ADK Dev UI at http://localhost:8000. Pick cargomind |
| ADK's own terminal runner for the same agent |
| Aliases for |
| Test suite |
Mission-control dashboard
uv run cargomind web # http://localhost:8080 (other port: --port 8090)Area | What you see and do |
Top bar | Status pills showing which models and APIs are live, the network clock (IST), and the Chaos Monkey slider (0–60%), which injects transient faults into tool and model calls live |
Watchtower | Proactive alerts (critical first) from the background scan. Click an alert to send its suggested question to the agent, or scan on demand |
Network pulse | KPI tiles: on-time rate, delayed and critical shipments, fleet utilisation, open POs and more. Refreshes every 10 s |
Shipments | Filterable table (ID, customer, city) of the seeded network |
Network map | Leaflet + OpenStreetMap map of hubs, cities and shipment lanes, coloured by status |
Ops agent chat | Streaming conversation with suggested questions, a new session button and photo attach (button, paste or drag-and-drop). The trace shows agent hand-offs, every tool call with its arguments and results, and the model that served each answer. Thumbs up/down + comment on answers feed the learning loop |
Self-healing journal | Live SSE feed of |
Method | Path | Purpose |
|
|
|
|
| Upload a delivery photo (multipart |
|
| Serve an uploaded photo |
|
|
|
|
| Distilled lessons + satisfaction stats |
|
| Network data (filters: |
|
| Recent journal events, stats, circuit-breaker states, chaos rate |
|
| SSE live healing journal |
|
| Read or set the chaos rate ( |
|
| Active Watchtower alerts ( |
|
| Run a Watchtower scan now; returns new and active alerts |
|
| Mode, live providers, component presence, library versions |
Example:
curl -N -X POST http://localhost:8080/api/chat -H "Content-Type: application/json" \
-d '{"session_id":"curl-1","message":"Where is SHP-1003?"}'ADK Dev UI
Google ADK ships a developer UI. CargoMind's package exposes its ADK App (agent graph + SelfHealingPlugin) in src/cargomind/__init__.py, so the dev UI runs exactly the same system.
uv run adk web src # http://localhost:8000
uv run adk web --port 8001 src # if 8000 is busyOpen http://localhost:8000. In the agent dropdown (top left), select
cargomind.Chat as usual, for example "Plan today's dispatch from Mumbai".
Use the Events list to inspect every model request and response, function call and function response, including the planner ⇄ critic iterations.
Use State to see the session state the agents pass to each other, such as
current_plan,plan_issues,dispatch_plan_summary,kpi_snapshot,risk_snapshotandstock_snapshot.
Notes: adk web also reads the repo-root .env through config.py. On Windows, ADK turns off auto-reload by itself, because reload is incompatible with the MCP stdio subprocess. For a terminal-only ADK session use uv run adk run src/cargomind.
MCP server
cargomind-logistics is a real Model Context Protocol server built with the Python MCP SDK. It exposes the operational database over stdio.
Tool | Arguments | Purpose |
|
| Status, location, carrier/vehicle, ETA, promised date |
|
| Filtered list, critical first |
|
| Event timeline |
|
| Write a status change + event |
|
| Stock vs reorder points |
|
| Raise a purchase order |
|
| Fleet, capacity, driver hours, refrigeration |
|
| Assign a truck to a shipment |
| – | Carriers, modes, rates, reliability |
| – | Warehouse directory |
| – | Network KPIs |
Resources: logistics://kpis and logistics://warehouses (JSON). A look-up that misses never throws. It returns {"status": "error", "error": ..., "suggestions": [closest valid IDs]} so the calling LLM can correct itself.
How CargoMind's own agents use it
The specialists get their MCP tools from mcp("track_shipment", ...) in mcp_tools.py. That creates a ResilientMcpToolset wrapping ADK's McpToolset, which spawns python -m cargomind.mcp_server.server over stdio. If the server can't start or stops answering, the toolset journals the fault, opens a breaker and serves the same tool names in-process, so the conversation never breaks. After the cooldown it reconnects and journals recovered.
Use it from Claude Desktop
Find the absolute path to your clone and to
uv(where uvon Windows,which uvon macOS/Linux).Open Claude Desktop → Settings → Developer → Edit Config. That opens
claude_desktop_config.json:Windows:
%APPDATA%\Claude\claude_desktop_config.jsonmacOS:
~/Library/Application Support/Claude/claude_desktop_config.json
Paste the contents of
deploy/claude_desktop_config.example.jsonand replace the path:{ "mcpServers": { "cargomind-logistics": { "command": "uv", "args": ["--directory", "/ABSOLUTE/PATH/TO/cargomind", "run", "cargomind", "mcp"], "env": { "PYTHONUTF8": "1" } } } }On Windows, escape backslashes (
"C:\\Users\\you\\cargomind"). If Claude Desktop can't finduv, put the full path touvin"command".Fully quit Claude Desktop (including the tray icon) and reopen it. Then ask: "Using cargomind-logistics, which critical shipments are delayed?"
The MCP server and the dashboard share data/cargomind.db. A status change made from Claude Desktop appears on the dashboard's next refresh.
Use it from Claude Code, Gemini CLI or the MCP Inspector
# Claude Code
claude mcp add cargomind-logistics -- uv --directory /ABSOLUTE/PATH/TO/cargomind run cargomind mcp
# MCP Inspector (needs Node.js 18+): browse tools, call them by hand
npx @modelcontextprotocol/inspector uv --directory /ABSOLUTE/PATH/TO/cargomind run cargomind mcpGemini CLI: add this to ~/.gemini/settings.json, then run /mcp inside Gemini CLI to see the tools.
{
"mcpServers": {
"cargomind-logistics": {
"command": "uv",
"args": ["--directory", "/ABSOLUTE/PATH/TO/cargomind", "run", "cargomind", "mcp"]
}
}
}Demo script
These are the same 8 prompts uv run cargomind demo runs, in one session. Type them into the dashboard or cargomind chat to drive them yourself. Wording varies by model. In zero-key mode the rule-engine answers with structured markdown tables.
# | Prompt | Routed to | What happens / what to look for |
1 |
|
| A |
2 |
|
| MCP |
3 |
|
|
|
4 |
|
|
|
5 |
|
| The feedback loop: the planner (pro tier) calls |
6 |
|
|
|
7 |
|
|
|
8 |
| concierge → | Stored as a lasting PREFERENCE. It appears under Lessons learned and is added to the concierge's instruction from the next turn on |
Bonus prompts that show off specific features:
Prompt | Shows |
| Human-in-the-loop: |
Attach a photo + | Gemini multimodal inspection: |
| Argument repair: watch for |
| Google Routes waypoint optimisation (or the OSRM / haversine fallback) |
| A multi-domain turn: the concierge calls several specialists in one go |
| Write action through MCP |
| The Disruption Autopilot: impact → reroutes + notice drafts in parallel → incident action plan awaiting approval |
The timed, click-by-click version for presenting is in docs/DEMO_SCRIPT.md.
Self-healing deep dive
CargoMind assumes things will break: free-tier quotas, flaky public APIs, hallucinated arguments, crashed subprocesses. It has five layers of defence, and every action is written to a journal you can watch live.
# | Layer | Where | What it heals |
1 | ResilientLlm model chain | Each agent's model is a chain: Gemini tier → Gemini backup → Claude/GPT → offline rule-engine. Transient errors (408/429/5xx, timeouts) are retried in place (0.4 s, 1.0 s). Other errors, such as a bad key or an unknown model, fall straight through. The request is rolled back to a pristine snapshot before every attempt. Each model has a circuit breaker (3 failures → skipped for 60 s). Every response is stamped | |
2 | SelfHealingPlugin (runner-wide ADK plugin) | before_tool: argument repair ( | |
3 | API provider fallback chains | Routes: Google Routes v2 → OSRM → haversine × road factor. Geocoding: Google → Nominatim → gazetteer. Weather: Open-Meteo → seasonal heuristic. Vision: Gemini → Pillow heuristic. Every result carries | |
4 | ResilientMcpToolset | If the MCP server can't be spawned or crashes, it serves identical tools in-process, opens a breaker and reconnects after the cooldown | |
5 | Chaos Monkey + healing journal |
|
Journal event kinds: fault (injected or real failure) · retry · fallback (next model or provider) · breaker_open / breaker_close · arg_repair · reflect (hint handed to the LLM) · recovered.
How to demo it
Recipe | Steps | What you'll see |
Chaos slider (best on stage) | Dashboard → drag Chaos Monkey to 30% → ask "Morning ops briefing" | The journal fills with |
Scripted chaos run |
|
|
Chaos for a whole session | Add | Every interface runs under chaos |
Kill Gemini, deterministically |
| Every Gemini call fails. Watch |
Bad API key | Set | Non-transient error → immediate fallback down the chain. The breaker then skips Gemini for 60 s |
Broken arguments | Ask "where is shp 1003" or "route bangalore to madras" |
|
No internet |
| All tools serve offline estimates flagged |
Feedback loops deep dive
CargoMind runs four feedback loops, two driven by agents and two by humans.
1. Agent ⇄ agent: plan → critique → revise (LoopAgent).
dispatch_planner (pro tier) calls propose_dispatch_plan. That builds a quick greedy plan assigning pending shipments to available own-fleet trucks, and writes state["current_plan"].
dispatch_critic runs on the critic tier: a different vendor when a Claude or OpenAI key is set. It calls validate_dispatch_plan, which checks every assignment for:
vehicle capacity
driver duty hours
cold-chain and dangerous-goods handling
weather risk
SLA for critical and express loads
diverging multi-drop routes, duplicate assignments, and critical shipments left without transport
Each issue has a severity (blocker / warning) and a suggested fix. The critic writes them to state["plan_issues"] and returns {valid, issues, score}.
If there are blockers, the next loop iteration runs the planner again. propose_dispatch_plan then revises the plan to fix them, using weather deferrals, driver-hour swaps, team drivers, carrier hand-offs for priority loads or corridor splits. When the plan is valid, the critic calls exit_loop. The loop is capped at 4 iterations. dispatch_reporter then summarises the revisions, fixed issues, assignments and deferred shipments. commit_dispatch_plan refuses an unvalidated revision unless the operator insists. Carrier hand-offs come back as booking actions; they are never auto-booked.
2. Human → agent: ratings, corrections and preferences that persist.
In the dashboard, the thumbs up/down + comment on each answer goes to
POST /api/feedback, which writes the SQLitefeedbacktable.In conversation, when the operator corrects the agent or says "remember / always / never / prefer…", the concierge calls
remember_operator_feedback. Text with always / never / prefer / avoid is also saved as a lasting preference.lessons()distils all of this into at most 8 deduplicated lines:PREFERENCE: …, thenAVOID: …(from negative comments), thenKEEP: …(from positive ones).render_lessons_block()appends those lines to the concierge's instruction. The instruction is a function (concierge_instruction), so ADK re-evaluates it on every turn. Feedback changes behaviour on the very next message, with no restart.The dashboard's Lessons learned panel shows what is currently being applied.
Check it from the terminal:
uv run python -c "from cargomind.feedback.store import render_lessons_block, stats; print(render_lessons_block()); print(stats())"3. Human-in-the-loop gates. Plans are only applied after "commit the plan". Notifications are only sent after approval. POs are raised and statuses changed only when explicitly asked. The agent proposes and the operator decides.
4. Tool → LLM: reflect and retry. Failed or not-found tool calls come back as structured errors with suggestions (closest valid IDs) and a healing_hint. Agents are instructed to correct their arguments and retry once before asking the user.
Disruption Autopilot and Watchtower
Disruption Autopilot (autopilot.py) handles a city-level event (cyclone, flood, strike, bandh, road closure, landslide) as one workflow. The concierge calls it as AgentTool(disruption_autopilot) when a message mentions autopilot, cyclone, flood, strike, bandh, closure, disruption, landslide or "alert in".
Step | Agent | Tool | Output ( |
1 |
|
| Exposed shipments, vehicles and warehouses, plus hub weather → |
2a (parallel) |
|
| Reroute / hold actions via an alternate hub, critical first, and vehicle moves out of the zone → |
2b (parallel) |
|
| Customer notice drafts for urgent shipments ( |
3 |
| – | Incident action plan: Situation, Exposure, Actions (owner + deadline), Customer comms, Approval needed |
The workflow produces proposals and drafts for operator review. Reroutes and vehicle moves must be applied manually in the transport system. To queue an approved notice in the simulated outbox, name its shipment, channel and message when asking the comms agent; there is no batch approval command. run_autopilot(city, event, severity) runs the three tools directly without an LLM; the CLI and tests use it.
uv run cargomind autopilot Chennai --event cyclone --severity high # direct tools, instant
uv run cargomind autopilot Chennai --event cyclone --severity high --agent # full multi-agent workflowWatchtower (watchtower.py) raises alerts before the operator asks. uv run cargomind web starts run_watchtower(60) as a background task in the server lifespan (set CARGOMIND_WATCHTOWER=0 to disable it). Each scan (scan_once() → {"new": [...], "active": [...]}) checks:
Check | Alert kind | Raised when |
SLA breach risk |
| ETA is later than |
Exceptions |
| Shipment status is |
Low stock |
| SKU below its reorder point with no open PO |
Fleet |
| Fuel below 20% or driver hours below 1 h |
Hub weather |
| Medium or high 24 h weather risk at one of 6 hubs. The suggested prompt runs the Disruption Autopilot |
Every alert has id, kind, severity, title, detail and a suggested_prompt. Existing alerts from a failing source are retained with stale: true until a healthy scan updates or resolves them. Other checks continue. See the alerts in the dashboard's Watchtower panel, at GET /api/alerts / POST /api/alerts/scan, or with uv run cargomind watchtower.
Evaluation
uv run cargomind eval --mode offline --out docs/EVAL_REPORT.md runs 18 scenarios (one fresh session each) through the real agent graph and scores routing, answer content, latency and healing events. Latest run, in offline rule-engine mode (no API keys, chaos 0%, in-process MCP). Full report: docs/EVAL_REPORT.md.
Metric | Value |
Task success | 18/18 (100%) |
Answer pass rate | 100% |
Routing precision / recall / F1 (micro) | 0.950 / 1.000 / 0.974 |
Routing exact-set match | 94.4% |
Latency p50 / p95 | 0.47 s / 2.85 s |
Runtime errors | 0 |
Every scenario reached the right specialist (recall 1.0). Precision is below 1.0 because one prompt is routed to an extra agent: the feedback prompt also calls tracking_agent. The harness caught two real rule-engine bugs, and both are fixed with regression tests: "Which" was parsed as warehouse WH-ICH, and "SKUs" was parsed as SKU-S. These numbers are for the offline rule-engine; live-model results will differ, so rerun with your keys (--mode online) to measure them.
Project structure
cargomind/
├── src/cargomind/
│ ├── __init__.py # exposes `app` / `root_agent` lazily, so `adk web src` finds the agent
│ ├── agent.py # the agent graph: concierge + 8 specialists (23 ADK agents), App + plugin
│ ├── autopilot.py # Disruption Autopilot: impact -> parallel reroutes + notice drafts -> action plan
│ ├── watchtower.py # proactive monitor: SLA, exception, stock, fleet and weather alerts
│ ├── runtime.py # ADK Runner, sessions, stream_chat() merging agent + healing events
│ ├── cli.py # `cargomind` command: chat / demo / web / mcp / doctor / reset-db / autopilot / watchtower / eval
│ ├── config.py # every env var, model ids, key detection, mode summary
│ ├── mcp_tools.py # ResilientMcpToolset: MCP client with in-process failover
│ ├── data/
│ │ ├── gazetteer.py # 20 Indian cities, aliases, IATA codes, haversine
│ │ └── db.py # SQLite schema, deterministic seed, queries, KPIs
│ ├── mcp_server/
│ │ └── server.py # cargomind-logistics MCP server: 11 tools + 2 resources (stdio)
│ ├── tools/
│ │ ├── geo.py # Google Routes v2 / Geocoding -> OSRM / Nominatim -> haversine
│ │ ├── weather.py # Open-Meteo -> seasonal heuristic
│ │ ├── planning.py # carrier quotes, ETA, dispatch propose / validate / commit
│ │ ├── vision.py # Gemini multimodal proof-of-delivery inspection -> Pillow heuristic
│ │ └── comms.py # customer notification drafts + simulated outbox
│ ├── healing/
│ │ ├── resilient_llm.py # cross-vendor model chain with retries, breakers, request rollback
│ │ ├── offline_llm.py # deterministic rule-engine that speaks the ADK model protocol
│ │ ├── plugin.py # SelfHealingPlugin (ADK BasePlugin)
│ │ ├── breaker.py # circuit breakers
│ │ ├── chaos.py # Chaos Monkey fault injection
│ │ └── journal.py # healing journal: ring buffer + SQLite + pub/sub
│ ├── evals/
│ │ ├── scenarios.py # 18 eval scenarios with expected routing and answer checks
│ │ └── runner.py # eval harness -> docs/EVAL_REPORT.md
│ ├── feedback/
│ │ └── store.py # ratings, preferences, lessons learned, remember_operator_feedback
│ └── web/
│ ├── server.py # FastAPI: REST + SSE chat / healing stream / alerts; starts the Watchtower
│ └── static/ # no-build dashboard (HTML/CSS/JS, Leaflet)
├── tests/ # pytest suite (data, MCP server, healing, feedback, offline LLM, autopilot, ...)
├── docs/ # ARCHITECTURE.md, JUDGING.md, DEMO_SCRIPT.md, CONTRACTS.md, EVAL_REPORT.md
├── deploy/
│ ├── cloudrun.sh # one-command Cloud Run deploy (Secret Manager aware)
│ └── claude_desktop_config.example.json
├── .github/workflows/ci.yml # lint + tests + offline e2e demo under chaos + Docker smoke test
├── Dockerfile / .dockerignore
├── pyproject.toml / uv.lock / .python-version
├── .env.example # copy to .env; every key optional
└── LICENSE # MITTesting and CI
uv run pytest # full suite
uv run pytest -q tests/test_healing.py
uv run ruff check src # lintThe tests are deterministic and need no keys. To match CI exactly (no network, real MCP stdio server):
CARGOMIND_OFFLINE=1 CARGOMIND_MCP_LOCAL=0 uv run pytest -q # macOS / Linux
$env:CARGOMIND_OFFLINE="1"; $env:CARGOMIND_MCP_LOCAL="0"; uv run pytest -q # PowerShellGitHub Actions runs on every push and PR, with zero keys:
uv syncruff check(advisory)pytest -qcargomind doctorthe full 8-step demo under 30% chaos, end to end through the real MCP stdio server
a separate job that builds the Docker image, runs it and waits for
/api/health
Docker
docker build -t cargomind .
docker run -p 8080:8080 --env-file .env cargomind # with your keys
docker run -p 8080:8080 cargomind # zero keysOpen http://localhost:8080. Useful variations:
docker run -p 8080:8080 --env-file .env -v cargomind-data:/app/data cargomind # keep DB + feedback across restarts
docker run -p 9000:9000 -e PORT=9000 cargomind # different port
docker run -p 8080:8080 -e CARGOMIND_CHAOS=0.3 cargomind # start with chaos onThe image is python:3.12-slim + uv. It installs exactly what uv.lock pins (uv sync --frozen --no-dev), runs as a non-root user, respects $PORT, and has a health check on /api/health. .env is never copied into the image.
Deploy to Google Cloud Run
Hosted Vercel demo
The public demo runs at https://cargomind-lilac.vercel.app with live provider keys configured through the Vercel CLI. Anonymous dashboard, health, KPI and static-asset requests returned HTTP 200. A live SSE tracking request completed with tool results and a final answer; its trace recorded Gemini backup and OpenAI providers.
Vercel uses temporary per-instance SQLite storage, uploads and session memory. Data can reset on a cold start. Click Scan now for Watchtower alerts; the continuous background scanner is disabled on serverless hosting. Local and Cloud Run operation retain the background scanner.
The deployment entrypoint is app.py; vercel.json selects FastAPI and a 300-second function limit. From a linked project, deploy with vercel --prod. Set provider keys through vercel env add NAME production and redeploy; keep secrets out of source control.
Google Cloud Run
Prerequisites: a Google Cloud project with billing enabled, and the gcloud CLI. Or use Cloud Shell, which already has everything.
gcloud auth login
gcloud config set project YOUR_PROJECT_ID
./deploy/cloudrun.sh # Windows: run from Git Bash, WSL or Cloud Shelldeploy/cloudrun.sh does the following:
Enables Cloud Run, Cloud Build and Artifact Registry.
Reads your keys from
.envwithout executing it.Stores each key in Secret Manager (
cargomind-google-api-key, …) and grants the runtime service accountsecretAccessor.Runs
gcloud run deploy --source .inasia-south1(Mumbai).Prints the URL.
Options:
--plain-envpasses the keys as plain env vars instead of secrets.--no-keysdoes a zero-key deploy.REGION=,SERVICE=,PROJECT_ID=,ENV_FILE=andSERVICE_ACCOUNT=override the defaults.
Manual equivalent (plain env vars, quickest):
gcloud run deploy cargomind --source . --region asia-south1 --allow-unauthenticated \
--memory 1Gi --timeout 3600 --max-instances 1 --session-affinity \
--set-env-vars GOOGLE_API_KEY=your-gemini-key,GOOGLE_MAPS_API_KEY=your-maps-key,ANTHROPIC_API_KEY=your-claude-keyManual equivalent with Secret Manager (recommended for anything public):
printf '%s' "your-gemini-key" | gcloud secrets create cargomind-google-api-key --data-file=-
PROJECT_NUMBER=$(gcloud projects describe $(gcloud config get-value project) --format='value(projectNumber)')
gcloud secrets add-iam-policy-binding cargomind-google-api-key \
--member="serviceAccount:${PROJECT_NUMBER}-compute@developer.gserviceaccount.com" \
--role="roles/secretmanager.secretAccessor"
gcloud run deploy cargomind --source . --region asia-south1 --allow-unauthenticated \
--memory 1Gi --timeout 3600 --max-instances 1 --session-affinity \
--set-secrets GOOGLE_API_KEY=cargomind-google-api-key:latestWhy these flags:
--max-instances 1+--session-affinitykeep chat sessions, the journal and the demo SQLite DB on one instance.--timeout 3600keeps dashboard SSE streams open.Cloud Run's filesystem is in-memory, so the demo DB re-seeds on each cold start. That is by design for a demo. See the Roadmap for managed persistence.
Troubleshooting and FAQ
Close and reopen the terminal after installing uv. If it still fails, add uv's directory to PATH: %USERPROFILE%\.local\bin on Windows, ~/.local/bin on macOS and Linux. On Windows, if the installer is blocked, run exactly powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex".
Run git config --global core.longpaths true. Enable Win32 long paths once, from an Administrator PowerShell:
New-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem" -Name "LongPathsEnabled" -Value 1 -PropertyType DWORD -Force
Then restart. Or simply clone to a short path such as C:\src\cargomind.
CargoMind already sets PYTHONUTF8=1 for child processes and switches the CLI to UTF-8 output. If your console still complains, set it for the shell before running: $env:PYTHONUTF8="1" (PowerShell) or set PYTHONUTF8=1 (cmd). Windows Terminal renders the output best. Python 3.12+ is required, and uv sync installs it.
Windows PowerShell 5.1 doesn't support &&. Run the commands on separate lines (as in the Windows setup above), or use PowerShell 7+.
Use uv run cargomind web --port 8090, or set PORT=8090. For the ADK UI use uv run adk web --port 8001 src. To find the process holding the port, run netstat -ano | findstr :8080 (Windows) or lsof -i :8080 (macOS/Linux).
Nothing to do: this is exactly what the self-healing chain is for. CargoMind retries twice, fails over to CARGOMIND_GEMINI_BACKUP, then to Claude/GPT, then to the offline engine. The model's breaker skips it for 60 s, and the journal shows each step. For sustained heavy use, enable billing on the AI Studio project or point CARGOMIND_GEMINI_FAST at a model with more quota.
Your key may not have access to a default model id. The chain falls back automatically. To fix it permanently, set CARGOMIND_GEMINI_FAST, CARGOMIND_GEMINI_PRO or CARGOMIND_GEMINI_BACKUP (or the Claude / OpenAI ids) in .env to models your account lists. uv run cargomind doctor prints the ids in use.
No usable model key was found, or every online model failed. Run uv run cargomind doctor. If live: is none, your .env is missing, empty or still has placeholders. It must be at the repo root and named exactly .env. Otherwise, check the healing journal for the fallback reason, for example an invalid key.
Google Maps isn't configured or rejected the call. Check that Routes API and Geocoding API are both enabled on the key's project, that billing is on, and that the key restrictions allow those APIs. Until then, the free OSRM or offline estimates are used and clearly flagged.
Use absolute paths: the repo path in --directory and, if needed, the full path to uv in "command". Fully quit Claude Desktop, including the tray icon, before reopening. Logs are in %APPDATA%\Claude\logs\mcp*.log (Windows) or ~/Library/Logs/Claude/mcp*.log (macOS). Run uv sync once in the repo first.
That's correct. It is a stdio server waiting for an MCP client. Press Ctrl+C, then connect it from Claude Desktop, Claude Code, Gemini CLI or the MCP Inspector.
uv run cargomind reset-db re-seeds the operational data. For a completely clean slate, including feedback, lessons and the journal history, stop all CargoMind processes and delete data/cargomind.db*. It is recreated on the next start.
Set CARGOMIND_OFFLINE=1. No network calls are made, and the whole demo, including dispatch planning, briefings and self-healing, still works on seeded data.
No. send_notification writes to a simulated outbox table (GET /api/outbox). Nothing leaves the machine.
On newer projects, source deploys build with the Compute Engine default service account. Grant it the Cloud Run Builder role:
gcloud projects add-iam-policy-binding YOUR_PROJECT_ID --member="serviceAccount:PROJECT_NUMBER-compute@developer.gserviceaccount.com" --role="roles/run.builder"
If you switch between --plain-env and Secret Manager on an existing service and see "already set with a different type", remove the old variables first, for example gcloud run services update cargomind --region asia-south1 --remove-env-vars GOOGLE_API_KEY.
Roadmap
Real integrations: carrier and TMS APIs, India's e-way bill and ULIP data, live GPS telematics in place of the seeded fleet.
Managed persistence: Firestore or Cloud SQL for operations data, sessions and the healing journal, so the system can scale beyond one instance.
Vertex AI Agent Engine deployment, and live-model runs of the eval harness in CI.
Optimisation: an OR-Tools VRP solver behind
propose_dispatch_plan, with time windows and cold-chain constraints.Learning: embedding-based retrieval of past feedback and incidents, plus per-operator preference profiles.
A2A protocol so carrier and warehouse partners' agents can negotiate directly with CargoMind.
Voice control-tower mode with the Gemini Live API. Auth / RBAC on the dashboard. OpenTelemetry → Cloud Trace.
Team
Name | Role | GitHub |
Anand B | Core platform, agents, self-healing and dashboard | |
Junaid Ahamed | Disruption Autopilot, Watchtower, CLI and evaluations |
License
MIT © 2026 CargoMind contributors.
Built with Google ADK, Gemini, Google Maps Platform, the Model Context Protocol, LiteLLM, FastAPI, Leaflet, OpenStreetMap / OSRM and Open-Meteo. Map data © OpenStreetMap contributors.
Available Tools
11 toolsassign_vehicleA
Assign an own-fleet vehicle to a shipment. Checks capacity and maintenance status; idempotent.
Args:
shipment_id: Shipment ID such as "SHP-1007".
vehicle_id: Vehicle ID such as "TRK-105".
Returns:
{"status": "ok", "warnings": [...], "vehicle": {...}} - warnings flag soft issues (vehicle in another
city, driver near the 10h limit, low fuel, cold-chain mismatch). Errors suggest alternative vehicles.
| Name | Required | Description | Default |
|---|---|---|---|
| vehicle_id | Yes | ||
| shipment_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does well: it discloses validation behavior (capacity and maintenance checks), idempotency, warning semantics (cross-city vehicle, driver hours, fuel, cold-chain mismatch), and that errors propose alternatives. It stops short of stating permission requirements or whether a failed validation rejects the assignment outright.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the purpose, then compact Args and Returns blocks. The Returns block is somewhat redundant given an output schema exists, but it is short and information-dense rather than padded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers purpose, parameters, validation behavior, warning categories, and failure behavior. Since an output schema exists, the return explanation is a minor duplication rather than a gap; only explicit permission/precondition details are missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, but the two parameters are named clearly and the description compensates with concrete example formats ("SHP-1007", "TRK-105") that the bare string schema lacks. More than adequate for a two-parameter tool.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Assign an own-fleet vehicle to a shipment') and scopes it to own-fleet, which implicitly separates it from the carrier-related siblings (list_carriers). An agent can distinguish this from track_shipment or list_vehicles immediately.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied by the verb and the own-fleet scoping, but there is no explicit when-to-use or when-not guidance, and no routing to an alternative for non-own-fleet assignments. It never says what to do when capacity or maintenance checks fail beyond 'errors suggest alternative vehicles'.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
check_inventoryA
Check stock levels per SKU and warehouse, including low-stock flags and any open purchase order.
Args:
sku: SKU ID ("SKU-107") or product name fragment ("insulin", "gloves"). Empty = all SKUs.
warehouse_id: Warehouse ID ("WH-BLR"), code ("BLR") or city ("Bangalore"). Empty = all warehouses.
low_stock_only: If true, only lines at or below their reorder point.
Returns:
{"status": "ok", "count", "low_stock_count", "items": [{sku, name, warehouse_id, qty_on_hand,
reorder_point, shortfall, low_stock, open_po, ...}]}.
| Name | Required | Description | Default |
|---|---|---|---|
| sku | No | ||
| warehouse_id | No | ||
| low_stock_only | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full load. It discloses that this is a read-style lookup and describes the shape and semantics of the returned item fields (shortfall, low_stock, open_po), but says nothing about permissions, scoping restrictions, or behavior when the result set is large. An output schema exists, so reciting return fields adds less value than it appears.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded purpose sentence followed by structured Args/Returns blocks, so the agent can parse it quickly. The Returns block restates information already carried by the output schema, which is mild redundancy, but nothing is bloated or buried.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a three-optional-parameter read tool with an output schema available, the description covers invocation semantics and result contents adequately. It omits anything about permission requirements, rate/cost behavior, or result-size limits when all SKUs and warehouses are requested, which are the remaining gaps.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate, and it does: each of the three parameters is explained with concrete value formats ('SKU-107', 'WH-BLR'/'BLR'/'Bangalore'), a fragment-matching convention for product names, and the meaning of empty/default values. This is exactly what the schema fails to provide.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Check stock levels per SKU and warehouse') and enumerates the payload of the result (low-stock flags, open purchase order), which clearly separates it from write-side siblings like create_reorder. It does not explicitly name a sibling it replaces, so it stops short of the top band.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives invocation context for each parameter (empty string means all SKUs / all warehouses) and defines low_stock_only operationally, which is useful. However, it never says when to prefer this tool over alternatives such as get_kpis or create_reorder, and there are no exclusions or prerequisites stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_reorderA
Raise a purchase order to replenish a SKU at a warehouse. Safe to retry: if an open PO already exists for the line it is returned with duplicate=true instead of creating another.
Args:
sku: SKU ID such as "SKU-107".
warehouse_id: Warehouse ID ("WH-BLR"), code or city.
qty: Units to order; 0 = automatic (tops stock up to 2x reorder point, min standard reorder qty).
Returns:
{"status": "ok", "duplicate": bool, "purchase_order": {id, qty, supplier, expected_by, ...}, "message"}.
| Name | Required | Description | Default |
|---|---|---|---|
| qty | No | ||
| sku | Yes | ||
| warehouse_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does so well: it discloses idempotent/retry-safe behavior, the duplicate-detection contract, and the auto-quantity side effect (qty=0 tops stock to 2x reorder point, min standard reorder qty). It omits permission requirements and any downstream effects (supplier notification, inventory mutation), keeping it short of a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the action and the retry-safety guarantee, then cleanly sectioned into Args and Returns. The Returns block restates what the output schema already declares, which is mild redundancy, but nothing else is padded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 3-parameter mutation tool with no annotations, the description covers action, idempotency, duplicate handling, and every parameter's semantics. An output schema exists, so the Returns summary is a bonus rather than a necessity, and no information an agent needs to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate, and it does for all three parameters: sku format example, warehouse_id accepting ID/code/city, and detailed qty semantics including the default 0 = automatic behavior. This is meaningfully more than the bare integer/string types in the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("Raise a purchase order to replenish a SKU at a warehouse") with the scope of the action. It is clearly distinguishable from every sibling, none of which create purchase orders; the closest siblings (check_inventory, list_shipments) are read operations on adjacent resources.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives real usage context: it is safe to retry, and an existing open PO is returned with duplicate=true rather than double-ordering. It stops short of explicitly naming when-not-to-use or a competing alternative tool, but no sibling overlaps this action, so the routing gap is minor.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_kpisB
Network health snapshot: on_time_rate (%), in_transit, delayed, exceptions, delivered_today, low_stock_skus, fleet_utilization (%), open_pos, critical_active and counts by status.
Returns:
KPI dict with status="ok".
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden, but it only lightly implies a safe read via 'snapshot' and states the return wrapper 'KPI dict with status="ok"'. It says nothing about permissions, caching/refresh semantics, or whether the snapshot is real-time — gaps that matter for a monitoring tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The metric list is front-loaded and the description is short. The 'Returns: KPI dict with status="ok"' line is largely redundant given an output schema exists, which is the one wasted fragment.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter read tool with a full output schema and no annotations, the description is nearly sufficient: it tells the agent what metrics come back and that the call is a snapshot. The missing piece is when to prefer this aggregate over the sibling list/status tools.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so the baseline is 4. There is nothing for the description to disambiguate, and the enumerated metric names usefully pre-announce the shape of the payload the agent will receive.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific resource (network health KPIs) and enumerates the exact metrics returned (on_time_rate, in_transit, delayed, exceptions, delivered_today, low_stock_skus, fleet_utilization, open_pos, critical_active). This is far more concrete than a tautology, though it never contrasts itself with siblings like check_inventory or track_shipment, which also surface operational status.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no explicit when-to-use guidance, no prerequisites, and no mention of alternatives. An agent must infer that this is the dashboard/aggregate call rather than one of the shipment- or inventory-specific siblings; the description does nothing to route that decision.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_carriersA
List carrier partners with modes, INR rate card (base_rate_per_km, per_kg_rate), reliability (0-1) and average speed - use for quoting and choosing a carrier.
Returns:
{"status": "ok", "count", "carriers": [...]}.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden. It discloses the return envelope ('status', 'count', 'carriers') and field meanings, which is useful, but says nothing about auth requirements, rate limits, caching/freshness, or whether the carrier set is static — mild gaps for a read-only listing.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose and usage are front-loaded in the first sentence, and the return block is compact. The 'Returns:' section partially duplicates the existing output schema, keeping it just short of maximally efficient.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple, parameterless listing tool with an output schema already present, the description covers what the tool is, what it returns, and why an agent would call it. Nothing needed to invoke it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes no parameters, so there is nothing to disambiguate; the baseline for a 0-param tool is 4. The description instead spends its detail budget on the returned fields, which is the right trade-off.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('List carrier partners') and enumerates the exposed fields (modes, INR rate card, reliability, average speed). No sibling tool deals with carriers, so the scope is unambiguous against list_shipments, list_warehouses, list_vehicles, etc.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
'use for quoting and choosing a carrier' gives a concrete use context, which is more than most list tools offer. It stops short of naming alternatives or stating when not to use it, but for a zero-param read tool the guidance is adequate.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_shipmentsA
List shipments, filtered and sorted (active first, critical first, then earliest promised delivery).
Args:
status: One of created, picked_up, in_transit, delayed, out_for_delivery, delivered, exception,
or "active" (anything not yet delivered/exception). Empty = all.
city: City name or alias (e.g. "Bangalore", "Bombay"); matches origin, destination or current city.
priority: standard, express or critical. Empty = all.
limit: Maximum rows to return (default 25).
Returns:
{"status": "ok", "count": n, "shipments": [...]} each with is_late / delay_hours.
| Name | Required | Description | Default |
|---|---|---|---|
| city | No | ||
| limit | No | ||
| status | No | ||
| priority | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the burden. It discloses the sort order and the response shape with is_late/delay_hours, which is useful. However, it doesn't state read-only nature explicitly, permission requirements, or pagination behavior (only a limit default).
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action and sort order, then organized Args/Returns. Slightly verbose with the multi-line enum listing but every element is informative.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Even without an output schema-explain requirement (it has one, though the description still describes the wrapper), the description covers filtering, sorting, and return shape adequately. Missing only explicit safety/read-only statement and cross-sibling guidance.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description must compensate – and it does well: it enumerates status values including the 'active' pseudo-value, explains city alias matching across origin/destination/current city, and gives the limit default. Only priority lacks an explicit default note (empty = all is stated).
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('List shipments') and adds the implicit sort order (active first, critical first, then earliest promised delivery), which distinguishes it from track_shipment and update_shipment_status.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied by the filtering args (status/city/priority/limit), but there is no explicit 'when to use vs track_shipment/shipment_history' guidance or exclusions. The agent can infer this is a filtered list, but the sibling routing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_vehiclesA
List own-fleet vehicles with capacity, current load, driver hours remaining and fuel.
Args:
status: available, on_route or maintenance. Empty = all.
city: Current city of the vehicle (name or alias). Empty = all.
Returns:
{"status": "ok", "count", "vehicles": [{id, type, capacity_kg, remaining_capacity_kg, status,
current_city, driver_name, driver_hours_today, driver_hours_remaining, fuel_pct, refrigerated}]}.
| Name | Required | Description | Default |
|---|---|---|---|
| city | No | ||
| status | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations exist, so the description carries the full behavioral burden. It implies a safe read and enumerates returned fields, but says nothing about pagination, result limits, permissions, or ordering for a list tool, leaving real gaps against the no-annotation baseline.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded purpose sentence followed by clean Args/Returns blocks with no filler. The Returns block largely restates the existing output schema, which is mild redundancy, but it is not verbose.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With only two optional parameters and an output schema already covering the return shape, the description supplies everything an agent needs to invoke the tool correctly. Only the missing behavioral details (limits, ordering) leave a small residual gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the schema contributes only titles and defaults. The description compensates by enumerating the status values (available, on_route, maintenance) and clarifying that city accepts a name or alias, which is meaningful added semantics.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('List own-fleet vehicles') plus the exact data surfaced (capacity, load, driver hours, fuel). 'Own-fleet' implicitly separates it from list_carriers, though no sibling is named explicitly, keeping it just short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Filter semantics are implied through the Args block ('Empty = all' for status and city), which tells the agent how to broaden results, but there is no statement of when to choose this over list_carriers, track_shipment, or other listing tools. Usage is inferable but not guided.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_warehousesA
List warehouses with city, coordinates, utilisation %, cold-chain capability and low-stock line count.
Returns:
{"status": "ok", "count", "warehouses": [...]}.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. 'List' implies a safe read, and the return shape is disclosed, but there is no statement about pagination, ordering, result-size limits, or freshness of the utilisation/low-stock figures. Adequate but thin for an unannotated tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short lines, front-loaded with the resource and its fields. The 'Returns:' block is arguably redundant with the output schema, but it is compact and does not bury the purpose.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-param read tool with an output schema already present, the description supplies what is needed: the resource and the fields each warehouse carries. Only the return-shape line duplicates the output schema, and nothing about result volume or pagination is stated.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so per the rubric the baseline is 4; there is no parameter semantics to explain beyond the implicit 'no filtering available' constraint, which the description does not state but the empty schema makes obvious.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('List') and resource ('warehouses') and even enumerates the fields returned (city, coordinates, utilisation %, cold-chain capability, low-stock line count). It is clearly distinct from the shipment/vehicle/carrier siblings, though it never explicitly says so.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No when-to-use statement, no alternatives, no exclusions. For a zero-parameter listing tool the intended use is largely self-evident, so the guidance is implied rather than absent, but nothing in the text routes the agent here versus check_inventory or get_kpis.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
shipment_historyA
Full chronological event trail (scans, checkpoints, delays, assignments) for one shipment.
Args:
shipment_id: Shipment ID such as "SHP-1003".
Returns:
{"status": "ok", "shipment_id": ..., "events": [{ts, status, city, note, source}, ...]}.
| Name | Required | Description | Default |
|---|---|---|---|
| shipment_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden. It discloses the semantic content of the response and implies a read-only operation, but says nothing about ordering guarantees, pagination or result caps for long trails, or any permission requirements — meaningful gaps for a history endpoint.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose sentence is front-loaded with the key scope words, and the Args/Returns blocks are terse and scannable. No filler or repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter read tool with an output schema present, the description covers purpose, the input format, and a sample response, so it is largely self-sufficient. The only shortfall is the absence of any note on result size or paging for long event trails.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description has to compensate and it does: it gives the expected ID format example ("SHP-1003"), which the bare string schema does not. Only one parameter exists and no additional qualifiers (date range, filters) are hinted at.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific resource and scope: a full chronological event trail (scans, checkpoints, delays, assignments) for one shipment. This clearly differs from a current-status tool like track_shipment, but the description never names or contrasts with any sibling, so the agent must infer the boundary.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is only implied by the words 'full chronological event trail', which suggests historical/audit retrieval versus a live-tracking sibling. There is no explicit when-to-use, when-not-to-use, or named alternative, so the routing guidance is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
track_shipmentA
Track a shipment: current status, location, ETA vs promised delivery, carrier, vehicle and recent events.
Use this first whenever the user mentions a specific shipment or order.
Args:
shipment_id: Shipment ID such as "SHP-1001" (also accepts "shp1001" or "1001").
Returns:
The shipment (status, priority, origin_city, destination_city, last_city, eta, promised_by,
is_late, delay_hours, hours_to_promise, carrier_name, vehicle, customer, weight_kg, notes)
plus ``recent_events`` (latest 5, newest last). On a miss: status="error" with suggestions.
| Name | Required | Description | Default |
|---|---|---|---|
| shipment_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations exist, so the description carries the full load, and it does disclose real behavior: accepted ID variants ('SHP-1001', 'shp1001', '1001'), that recent_events returns only the latest 5 newest-last, and the miss behavior (status="error" with suggestions). It omits auth/permission needs and rate limits, which keeps it from a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the purpose and usage trigger before the Args/Returns blocks, and every sentence carries information. The Returns block restating 15 output fields is somewhat redundant given an output schema exists, mildly diluting conciseness.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter read tool with an output schema, the description supplies the identifier format, the priority trigger, and error behavior. It is essentially complete, with only minor gaps around permissions and any pagination/limit nuance for recent_events.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the schema provides no parameter meaning at all. The description compensates fully for the single parameter by giving a concrete example ID and documenting that normalized/short forms are also accepted, which is information an agent could not get from the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Track a shipment') and enumerates the exact facets returned: status, location, ETA vs promised delivery, carrier, vehicle, recent events. It implicitly separates itself from list_shipments via 'a specific shipment or order' but never names a sibling, so it stops short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
'Use this first whenever the user mentions a specific shipment or order' is an explicit trigger condition with a priority ordering relative to other tools. It gives no when-not guidance or named alternative (e.g. list_shipments for broad queries), so it is clear context without exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_shipment_statusA
Change a shipment's status and log a history event (e.g. mark delayed, delivered, exception).
Args:
shipment_id: Shipment ID such as "SHP-1002".
status: New status: created, picked_up, in_transit, delayed, out_for_delivery, delivered or exception.
city: Optional city where the update happened (defaults to the current/destination city).
note: Short human-readable reason, e.g. "Rain on NH-48, 6h delay". Stored as the shipment note.
Returns:
{"status": "ok", "previous_status": ..., "shipment": {...}, "event": {...}} or an error with valid values.
| Name | Required | Description | Default |
|---|---|---|---|
| city | No | ||
| note | No | ||
| status | Yes | ||
| shipment_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does reasonably well: it discloses a side effect beyond the status change (a history event is logged), specifies that the note is persisted as the shipment note, and that invalid input returns an error listing valid values. It stops short of stating permissions, reversibility, or idempotency, which matters for a mutation tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The one-line purpose is front-loaded, and the Args/Returns block is tightly formatted with one line per parameter and no filler. Every sentence carries information an agent needs to invoke the tool correctly.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a four-parameter mutation tool with no annotations, the definition covers purpose, all parameters, the side effect, and the return shape, so an agent has what it needs. The only gap is the absence of any explicit routing guidance against the many read-oriented sibling tools.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate and it does: it documents all four parameters with an ID format example ('SHP-1002'), the complete closed set of valid status values (absent from the schema, which has no enums), and the default behavior of city when omitted.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Change a shipment's status') and adds the important side effect that a history event is logged, which an agent cannot infer from the name alone. It does not explicitly differentiate itself from siblings such as track_shipment or shipment_history, but the mutation-plus-audit purpose is unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied rather than stated: the examples ('mark delayed, delivered, exception') show the intended scenario, but there is no explicit when-to-use vs sibling guidance (e.g. vs track_shipment, which appears read-only) and no stated prerequisites or exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
11 tool updates
v0.1.0- First observed
assign_vehicle - First observed
check_inventory - First observed
create_reorder - First observed
get_kpis - First observed
list_carriers - First observed
list_shipments - First observed
list_vehicles - First observed
list_warehouses - First observed
shipment_history - First observed
track_shipment - First observed
update_shipment_status
TDQS
Scored across 11 tools
Tools are cleanly separated by resource and action: shipment tracking/list/history/status update, inventory/warehouses/reorders, fleet assignment, carriers, and KPIs. Overlaps are minimal; track_shipment and shipment_history differ in scope (current status plus recent events vs full event trail).
Names are consistently snake_case and mostly follow a verb_noun pattern such as track_shipment, list_shipments, update_shipment_status, check_inventory, create_reorder, assign_vehicle, and get_kpis. The main deviation is shipment_history, which is noun_noun rather than action-first, but it remains readable and predictable.
11 tools is well-scoped for a logistics control tower, covering shipments, inventory, warehouses, fleet, carriers, and KPIs without obvious filler. Each tool maps to a clear operational task.
Core operational workflows are covered: track/update shipments, inspect inventory, raise reorders, assign vehicles, and monitor KPIs. Gaps remain around shipment creation/cancellation and purchase-order or vehicle lifecycle management, but these are minor for a monitoring and dispatch-oriented server.
Maintenance
Related MCP Connectors
WMS & logistics intelligence: live freight & shipping rates, port data, inventory, fleet, KPIs
India shipping for AI agents: Shiprocket courier serviceability, create orders, track AWB.
AI-ready GIS, geofencing, DataSynch, CRM, inventory, routing, APIs, telemetry and workflows.
AI-native platform: cybernetic freight agents transact, verify, find services. Get verified leads.
Related MCP Servers
- AlicenseAqualityDmaintenanceThe first logistics/WMS MCP server for AI agents. Rate shopping, inventory management, order tracking, fleet logistics, AI-powered route optimization, demand forecasting, and supply chain analytics. 18 tools across 3 tiers.207 npm1MIT
- AlicenseNot gradedqualityBmaintenanceProvides supply chain and shipping tools including shipment tracking, route optimization, warehouse inventory management, delivery ETA estimation, and customs documentation. Enables logistics operations through natural language interactions with Claude.6 npm58 PyPIMIT
- FlicenseAqualityCmaintenanceEnables AI agents to query orders, manage routes, track drivers, and analyze delivery performance on the FleetSync last-mile delivery platform through natural language.18-
- AlicenseNot gradedqualityAmaintenanceProvides 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.1MIT