indian-parcel-mcp
v0.1.5
Published
India-focused MCP server for shipment tracking, deadline-aware reasoning, and escalation guidance.
Maintainers
Readme
Why This Exists
Most tracking tools answer one narrow question: "what did the carrier last say?" For high-stakes shipments, that is not enough.
indian-parcel-mcp turns Indian courier tracking into structured judgment for LLM clients. It does not just expose scan events; it returns a verdict such as on_track, at_risk, delayed, stuck, exception, or unknown, with a conservative delivery window, deadline buffer, anomaly signals, and escalation next steps.
The project was born from a real deadline-sensitive shipment: visa documents moving from Muzaffarpur to Bangalore with an embassy clock running. Generic trackers could show JSON. They could not say whether the parcel was likely to arrive in time, or what to do next.
What It Does
| Capability | What your MCP client gets |
|---|---|
| Carrier detection | AWB-pattern detection for Blue Dart, DTDC, Delhivery, and India Post / Speed Post. |
| Live tracking | Best-effort public portal tracking through carrier adapters, with safe unknown fallback when blocked or unstable. |
| Normalization | Carrier-specific scan text mapped into consistent shipment phases and status verdicts. |
| Deadline reasoning | needed_by support with predicted delivery windows, confidence, and buffer_hours. |
| Anomaly detection | Signals for stale scans, low scan density, RTO, exception flags, and stuck out-for-delivery cases. |
| Escalation guidance | Carrier-aware playbooks with privacy-safe scripts and contact paths. |
| Local watchlist | SQLite-backed watch storage with explicit refresh, change detection, and persisted monitoring state. |
| Observability | Lightweight health snapshot for carrier failures, cache hits, parser drift, and watch refresh runs. |
Supported Carriers
| Carrier | AWB shape | Phase 1 behavior | Parser tests |
|---|---|---|---:|
| Blue Dart | 8-11 digits | Live best-effort tracking | Yes |
| DTDC | 1-2 letters + 7-9 digits | Best-effort adapter with conservative fallback | Yes |
| Delhivery | 14 digits | Best-effort adapter with conservative fallback | Yes |
| India Post / Speed Post | XX#########IN | Best-effort adapter with conservative fallback | Yes |
Carrier portals change often and may block automated access. This server treats uncertainty as a first-class result: when it cannot fetch or parse confidently, it returns a structured unknown response instead of inventing confidence.
Quickstart
Clone and build the server:
npm install
npm run buildRun the MCP server over stdio:
node dist/src/server.jsDuring development, run it directly with tsx:
npm run devYou can run indian-parcel-mcp directly without global installation using npx:
npx -y indian-parcel-mcpAdd To Your MCP Client
Configure your preferred MCP client to use the published package via npx (recommended) or from your local build.
MCP Configuration File Paths
Below are the default configuration file paths for popular MCP clients:
| Client / Agent | Scope | Configuration File Path |
|---|---|---|
| Claude Desktop | Global (macOS) | ~/Library/Application Support/Claude/claude_desktop_config.json |
| | Global (Windows) | %APPDATA%\Claude\claude_desktop_config.json |
| Cursor | Global | ~/.cursor/mcp.json |
| | Project | .cursor/mcp.json |
| Cline | Global | ~/.cline/data/settings/cline_mcp_settings.json |
| | Project | .cline/mcp.json |
| Roo Code | Global (macOS) | ~/Library/Application Support/Code/User/globalStorage/rooveterinaryinc.roo-cline/settings/cline_mcp_settings.json |
| | Global (Windows) | %APPDATA%\Code\User\globalStorage\rooveterinaryinc.roo-cline\settings\cline_mcp_settings.json |
| | Project | .roo/mcp.json |
| Windsurf | Global (macOS) | ~/.codeium/windsurf/mcp_config.json |
| | Global (Windows) | %APPDATA%\Codeium\Windsurf\mcp_config.json |
| Antigravity CLI / Editor | Global | ~/.antigravitycli/mcp.json |
Claude Desktop
Add this to your Claude Desktop configuration file (located at the path above):
{
"mcpServers": {
"indian-parcel": {
"command": "npx",
"args": ["-y", "indian-parcel-mcp"]
}
}
}Cursor
Add this to either your global or project-specific mcp.json file:
{
"mcpServers": {
"indian-parcel": {
"command": "npx",
"args": ["-y", "indian-parcel-mcp"]
}
}
}Cline / Roo Code
Add this to your global settings file or project settings file:
{
"mcpServers": {
"indian-parcel": {
"command": "npx",
"args": ["-y", "indian-parcel-mcp"]
}
}
}Windsurf
Add this to your Windsurf configuration file:
{
"mcpServers": {
"indian-parcel": {
"command": "npx",
"args": ["-y", "indian-parcel-mcp"]
}
}
}Codex
codex mcp add indian-parcel -- npx -y indian-parcel-mcpOpenCode
{
"mcp": {
"indian-parcel": {
"type": "local",
"command": ["npx", "-y", "indian-parcel-mcp"],
"enabled": true
}
}
}Antigravity CLI / Editor
Add this to your Antigravity MCP config:
{
"mcpServers": {
"indian-parcel": {
"command": "npx",
"args": ["-y", "indian-parcel-mcp"]
}
}
}Local Development (Optional)
If you are developing or contributing to indian-parcel-mcp and want to run it from your local cloned source:
- Build the project:
npm run build - Reference the absolute path to your built
server.jsfile in your client's config:
{
"mcpServers": {
"indian-parcel-dev": {
"command": "node",
"args": ["/path/to/indian-parcel/dist/src/server.js"]
}
}
}A template local configuration is available in examples/claude-desktop-config.json.
Ask It Like This
Once connected, ask your MCP client directly:
Track this India package with indian-parcel: 21098765432Use track_shipment for AWB 18098765432. It must arrive before 2026-05-26T12:00:00+05:30.Diagnose this shipment and tell me whether I should escalate today: EA123456789INThe server descriptions intentionally guide clients toward Indian couriers for bare numeric AWBs, instead of drifting to unrelated non-India carriers.
Tool Reference
| Tool | Purpose |
|---|---|
| track_shipment | Track an Indian shipment, normalize carrier events, and return deadline-aware reasoning. |
| track_india_parcel | Alias optimized for clients that respond better to explicit India package wording. |
| detect_carrier | Infer the likely Indian carrier from an AWB. |
| detect_india_carrier | India-specific carrier-detection alias. |
| estimate_eta | Estimate route-level delivery windows from carrier and PIN codes. |
| diagnose_shipment | Track, detect anomalies, and generate escalation guidance. |
| watch_shipment | Persist a shipment in the local SQLite watchlist. |
| list_watches | List watched shipments and their last known monitoring state. |
| refresh_watches | Refresh one watch or all watches, detect changes, and persist results. |
| remove_watch | Remove a watch from local storage. |
| get_observability | Inspect carrier health, parser drift, and watch refresh counters. |
Example Outputs
Track A Deadline-Sensitive Shipment
Input:
{
"awb": "1234567890",
"needed_by": "2026-05-26T12:00:00+05:30",
"origin_pincode": "842001",
"destination_pincode": "560001"
}Output shape:
{
"awb": "1234567890",
"carrier": "bluedart",
"status": "at_risk",
"normalized_phase": "in_transit",
"current_location": "Delhi Hub",
"last_scan_at": "2026-05-24T08:10:00.000+05:30",
"predicted_delivery": {
"p50": "2026-05-25T20:10:00.000+05:30",
"p90": "2026-05-26T08:10:00.000+05:30",
"confidence": 0.82,
"basis": "historical_data"
},
"needed_by": "2026-05-26T12:00:00+05:30",
"buffer_hours": 3.8,
"events": [],
"reasoning": "Currently at Delhi Hub with latest scan ... The delivery buffer versus the deadline is about 4 hours.",
"fetched_at": "2026-05-24T09:00:00.000+05:30"
}Diagnose A Shipment
{
"awb": "1234567890",
"needed_by": "2026-05-26T12:00:00+05:30",
"purpose": "visa documents"
}Returns:
{
"status": {},
"anomalies": [
{
"type": "stale_scan",
"severity": "warning",
"description": "Latest scan is older than the configured threshold.",
"detected_at": "2026-05-24T09:00:00.000Z"
}
],
"escalation_playbook": [
{
"step": 1,
"action": "Contact carrier support with AWB and latest scan details.",
"channel": "phone",
"expected_outcome": "Confirm whether the shipment is moving and request a delivery commitment."
}
],
"reasoning": "Detected 1 anomaly signal(s): stale_scan. Currently at ..."
}Watch And Refresh
{
"awb": "1234567890",
"needed_by": "2026-05-26T12:00:00+05:30",
"label": "Visa documents"
}Then refresh later:
{}refresh_watches returns each checked watch, whether the state changed, the latest status, anomaly signals, and any refresh error.
Architecture
flowchart LR
Client["MCP client"] --> Server["indian-parcel-mcp"]
Server --> Detect["AWB detection"]
Detect --> Adapters["Carrier adapters"]
Adapters --> Normalize["Normalized scans"]
Normalize --> Reason["Deadline reasoner"]
Reason --> Diagnose["Anomaly + escalation"]
Server --> Watch["SQLite watchlist"]
Server --> Health["Observability snapshot"]The server is intentionally local-first. It runs over stdio, stores watchlist state in local SQLite, validates inputs and outputs with Zod schemas, and keeps carrier failures observable without leaking sensitive shipment data.
🌊 Complete End-to-End Tracking Flow
When an LLM requests tracking details for a shipment, the request goes through cache lookup, rate limiting, selective HTML scraping, and intelligence-layer reasoning before returning a final parsed verdict.
sequenceDiagram
autonumber
actor LLM as LLM Client
participant Server as MCP Server
participant Cache as LRU Cache
participant Rate as Rate Limiter
participant AWB as AWB Detector
participant Adapt as Carrier Adapter
participant HTTP as HTTP Client
participant Intel as Intelligence Layer
participant Web as Carrier Public Portal
LLM->>Server: track_shipment({ awb, needed_by })
Server->>Cache: Query AWB Cache (by AWB key)
alt Cache Hit (within 90 seconds)
Cache-->>Server: Cached Raw Result
Note over Server: Skip network requests!
else Cache Miss
alt Carrier is not specified
Server->>AWB: detect_carrier(awb)
AWB-->>Server: Detected Carrier(s) + confidence
end
Server->>Rate: Request Rate Token
alt Rate Limit Exceeded
Rate-->>Server: Throw RateLimitError
Server-->>LLM: Return status: "unknown" (Rate limited)
else Rate Limit OK
Server->>Adapt: track(awb)
Adapt->>HTTP: Fetch Tracking Page
HTTP->>Web: HTTP GET/POST with realistic UA and jitter
Web-->>HTTP: HTML Tracking Response
HTTP-->>Adapt: HTML String
Adapt->>Adapt: Parse HTML via Cheerio
Adapt-->>Server: RawTrackingResult (parsed events & status)
Server->>Cache: Write result to Cache (90s TTL)
end
end
Server->>Intel: deadline_reasoner.ts (RawTrackingResult + needed_by)
Intel->>Intel: Analyze latest scan events & status code
alt needed_by is provided
Intel->>Intel: Run Route SLA / Heuristic check
Intel->>Intel: Compute p50 / p90 transit window
Intel->>Intel: Calculate buffer hours & final status verdict
else no needed_by
Intel->>Intel: Apply default fallback predictions
end
Intel-->>Server: ShipmentStatus (with verdict, ETA basis, and 1-3 sentence reasoning)
Server-->>LLM: Return ShipmentStatus JSON-RPC ResponseDesign Principles
- Prefer one reliable carrier path over many fragile integrations.
- Return structured uncertainty instead of pretending blocked carrier portals worked.
- Keep responses LLM-friendly: compact JSON plus reasoning that can be paraphrased directly.
- Treat ETA confidence as operational guidance, not a statistical guarantee.
- Redact sensitive shipment data from logs and public escalation text.
- Protect parsers with carrier fixtures and protocol-level tests.
Development
npm install
npm run lint
npm run test
npm run buildUseful commands:
npm run typecheck
npm run pack:checkThe local SQLite watchlist defaults to parcel.sqlite in the project root. Override it with PARCEL_MCP_DB_PATH; BHARAT_LOGISTICS_DB_PATH is also supported for backward compatibility. Set LOG_LEVEL to tune structured logging.
The test suite covers carrier parsers, AWB detection, SLA lookup, deadline verdicts, anomaly detection, escalation logic, observability, watchlist monitoring, and MCP protocol schemas.
Contributing Carriers
- Add an AWB regex entry in data/awb_patterns.json.
- Implement a
CarrierAdapterinsrc/carriers/. - Add contact metadata in data/carrier_contacts.json.
- Add fixture HTML and parser tests under tests/carriers.
- Document whether live support is full or best-effort.
Roadmap
| Stage | Focus | |---|---| | Phase 1 | Reliable India-focused MCP core, Blue Dart vertical slice, parser fixtures, watchlist, explicit refresh, and observability. | | Phase 2 | Broader live carrier coverage where feasible, notification hooks, expanded SLA data, and HTTP transport for remote MCP clients. | | Phase 3 | SMS and email ingestion, community-reviewed SLA contributions, richer parser-drift triage, dashboarding, and MCP registry submission. |
Package Name
The npm package for this project is indian-parcel-mcp.
License
MIT LICENSE.
