Skip to main content
Glama

inventory-doctor

Multi-source inventory sync diagnostics — find the SKUs you're overselling without knowing it.

Compare two inventory snapshots (CSV exports or live Shopify stores) and get a report of everything that doesn't line up: SKU mismatches, oversell risk, blank cells masquerading as zeros, barcode conflicts, and more.

Your data never leaves your machine. CSV files are parsed locally; Shopify API calls go directly from your computer to your own stores over HTTPS. There is no server, no telemetry, no upload.

Install & run

npm install          # or: pnpm install
npm run build        # produces dist/cli.js (with shebang)

# zero-credential path: two CSV exports
npx tsx src/cli.ts diff fixtures/shopify-store-a.csv fixtures/shopify-store-b.csv
# or after build / npm link:
inventory-doctor diff a.csv b.csv

Related MCP server: DataClaw MCP Server

What it looks like

Running inventory-doctor diff fixtures/shopify-store-a.csv fixtures/shopify-store-b.csv against the bundled sample files (which deliberately contain one of every problem):

inventory-doctor — sync diagnosis
============================================================
Sources: shopify-store-a  vs  shopify-store-b
  shopify-store-a: 13 records
  shopify-store-b: 12 records

Sync health score: 33/100
  exact match: 5 · minor drift: 0 · severe drift: 4 · unmatched: 6 (of 15)

CRITICAL (8)
------------------------------------------------------------
[CRITICAL] SKU "DUP-100" appears 2 times in shopify-store-a with different quantities
[CRITICAL] SKU "ORPHAN-A" exists in shopify-store-a but is missing from shopify-store-b
[CRITICAL] "OVER-1" is out of stock in shopify-store-a (0) but shows 8 available in
           shopify-store-b — you may be selling stock you don't have
[CRITICAL] "BLANK-1" has a BLANK quantity cell in shopify-store-a (not "0") while
           shopify-store-b tracks a real quantity — an import may read this as 0
[CRITICAL] Barcode 9999999 maps to 2 different SKUs across sources
           ("BC-A" in shopify-store-a vs "BC-B" in shopify-store-b)
...

WARNING (5)
------------------------------------------------------------
[WARN]     SKU differs only by letter case: "ABC-123" (a) vs "abc-123" (b)
[WARN]     SKU matches only after removing whitespace/invisible characters
[WARN]     "CONT-1" allows overselling ("continue selling when out of stock") with quantity 0
...

INFO (3)
------------------------------------------------------------
[INFO]     Possible prefix/suffix variant: "GHI-789" (a) vs "SHOP-GHI-789" (b)
[INFO]     Sync health score: 33/100 — 5 exact, 0 minor drift, 4 severe drift, 6 unmatched
[INFO]     "UNTRACKED-1" has inventory tracking OFF in shopify-store-a but is
           stock-managed in shopify-store-b

The full output is checked in as fixtures/expected-report.md — it's a living document verified by the test suite.

The exit code is 1 when critical findings exist, so you can wire this into CI or a cron job.

The six diagnostic rules

Rule

What it catches

Severity

sku-mismatch

Case-only / whitespace / prefix-suffix SKU variants, orphan SKUs, one-to-many duplicates within one source

info → critical

oversell-risk

Quantity ≤ 0 on one side but > 0 on the other; "continue selling when out of stock" with empty stock; drift beyond threshold

warning → critical

blank-vs-zero

A blank quantity cell vs an explicit 0 — the classic "bulk import wiped my inventory" root cause

critical

barcode-crosscheck

Same barcode, different SKUs across sources — silent mapping misconfiguration

critical

quantity-drift

Overall sync health: % exact / minor drift / severe drift / unmatched → health score 0–100

info

untracked

Inventory tracking disabled in one source while another manages stock

info

Blank vs "0" is a first-class distinction. CSV parsers love turning empty cells into 0; this tool keeps quantity: null strictly separate from quantity: 0 all the way through.

Supported inputs

  • Shopify product CSV — both header generations are recognized (Variant SKU and the current SKU, Variant Inventory Qty and Inventory quantity, etc.)

  • Shopify inventory CSV — both layouts: the long "All states" table (one row per variant × location) and the wide "Available" table (location names as column headers, inferred automatically)

  • Anything else — alias-based column probing (Amazon-style seller-sku/quantity TSVs work out of the box), plus explicit mapping when guessing fails:

inventory-doctor diff shopify.csv erp.csv --map sku="Item Code" --map quantity="Stock Count"

SKU normalization (trim, case folding, full-width → half-width, zero-width character removal) is used only for comparison — reports always show your raw SKU values.

Multi-location aware. When both sources carry a location dimension (inventory CSV long/wide, or the API), quantities are compared per (SKU, location): a location-level stockout or drift is reported at that location and never hidden by summing across locations, and a SKU stocked at two locations is not mistaken for a duplicate. When one side has no location dimension (product CSV), its per-SKU quantity is compared against the other side's cross-location sum. See fixtures/shopify-inventory-c.csv / -d.csv (long format) and fixtures/shopify-inventory-wide-e.csv / -f.csv (wide format) for worked examples.

Shopify Admin API (optional)

Pull live snapshots instead of exporting CSVs. Create inventory-doctor.json in the project directory (or ~/.config/inventory-doctor/config.json):

{
  "stores": [
    // Mode 1: existing static token (shpat_... — still works if you already have one)
    { "name": "store-a", "domain": "a.myshopify.com", "accessToken": "env:STORE_A_TOKEN" },
    // Mode 2: client credentials grant (the current way to create app credentials)
    { "name": "store-b", "domain": "b.myshopify.com",
      "clientId": "env:STORE_B_CLIENT_ID", "clientSecret": "env:STORE_B_SECRET" }
  ]
}

Credentials support "env:VAR_NAME" references so secrets stay out of files. Then:

inventory-doctor diff --store store-a --store store-b   # store vs store
inventory-doctor diff --store store-a --csv b.csv       # mixed mode

Details that matter:

  • API version pinned to 2026-07 (/admin/api/2026-07/graphql.json).

  • Inventory is read via quantities(names: [...]) — the old InventoryLevel.available field no longer exists.

  • Tokens from client credentials live 24h; they're cached and refreshed 60s early, not re-requested per call.

  • Rate limiting is adaptive: every response's extensions.cost.throttleStatus.currentlyAvailable drives a slow-down before the bucket empties; HTTP 429 / THROTTLED backs off 1s and retries. No plan-specific rate numbers are hardcoded.

  • Read-only scopes only: read_inventory, read_products, read_locations.

Client credentials limitation: the app and the store must belong to the same Shopify org. That covers "a merchant building a tool for their own store". Agencies managing client stores will get shop_not_permitted and need full OAuth — which this tool does not implement (v1).

MCP server (use it from Claude Code and other agents)

Add to your .mcp.json:

{
  "mcpServers": {
    "inventory-doctor": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "inventory-doctor", "mcp"],
      "env": { "SHOPIFY_CLIENT_SECRET": "${SHOPIFY_CLIENT_SECRET}" }
    }
  }
}

Three tools are registered:

  • diff_inventory(sourceA, sourceB, configPath?) — full diagnosis, returns the JSON report

  • explain_sku(sku, sources, configPath?) — one SKU's raw values and findings across all sources (for follow-up questions)

  • inventory_health(sources, configPath?) — lightweight health-score summary

Every source argument accepts either a CSV file path or store:<name> (a store from inventory-doctor.json, credentials resolved from env vars) — so an agent can diff two live stores, or a store against a CSV, in one call. configPath is only needed when the config file is not in a default location.

stdout is reserved for JSON-RPC; all logging goes to stderr.

Honest limitations

  • Snapshot diffing only. This compares two snapshots taken now. It does not do time-series detection (e.g. "this SKU gets silently zeroed every night") — that needs snapshot history and is planned for v2.

  • Client credentials = same org only, as described above. No OAuth flow in v1.

  • Amazon report headers vary by marketplace and report options; detection is best-effort via column aliases, and --map is the escape hatch.

  • Product CSVs carry no per-location inventory; multi-location diagnosis needs the inventory CSV export or the API.

Development

npm test             # vitest — rules, CSV adapters, token cache, throttle logic
npm run dev -- diff fixtures/shopify-store-a.csv fixtures/shopify-store-b.csv
npm run build        # tsc + shebang
npm run check:stdout # guards the MCP stdout discipline

Architecture: src/core/ is a pure-function diagnostic kernel ((records: InventoryRecord[]) => Finding[], zero I/O); src/adapters/ turn CSVs and the Shopify API into that intermediate representation; CLI and MCP layers only parse arguments and format output. Adding a new source (WooCommerce, BigCommerce, …) means adding one adapter, no refactor.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.

No tool schema history has been recorded yet.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    C
    maintenance
    AI-first CSV analysis tool that enables AI agents to analyze, query, and audit large CSV files directly within conversations, turning raw data into actionable insights.
    2
    -
  • A
    license
    A
    quality
    D
    maintenance
    Enables Shopify store owners to get actionable business insights such as sales comparisons, inventory alerts, and recommendations, transforming raw data into meaningful decisions.
    10
    22
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables AI agents to manage Shopify stores via natural language, with tools for products, orders, inventory, customers, and analytics.
    24
    MIT

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/shidesheng0218/inventory-doctor'

If you have feedback or need assistance with the MCP directory API, please join our Discord server