Skip to main content
Glama
vinamrasangal

Zoho Inventory MCP Connector

Zoho Inventory MCP Connector

CI Python MCP License

A private, read-only connector that lets an AI agent answer a merchant's day-to-day questions from Zoho Inventory: stock levels, reorder alerts, sales orders and customers. It is exposed as an MCP server, so it plugs into Agent Studio, Claude, Cursor or any other MCP host.

"What do I need to reorder?" · "Can we ship 10 saffron packs from Mumbai?" · "What's still open for Chaayos?" · "Has SO-00087 shipped?"

What's included

  • OAuth 2.0: browser login with CSRF state, multi-data-centre support, refresh tokens, single-flight refresh, revoke on logout, and a 0600 token store. A headless Self Client flow is available for servers. See docs/AUTH.md.

  • 11 list / get / search tools with typed input and output schemas, plus readOnlyHint annotations. Spec: docs/tool-spec.json.

  • Rate-limit handling that prevents 429s rather than just retrying them: a sliding-window limiter, a concurrency cap, a daily budget that protects the merchant's shared quota, and Retry-After-aware backoff with jitter.

  • Errors designed for agents: each failure tells the model what to do next, so it doesn't loop.

  • Runs without a Zoho account: a high-fidelity mock Zoho (OAuth and Inventory API) powers the tests, the demo and local development.

  • 45 tests and CI, including a test that drives the server over stdio exactly as an agent host would.

  • A clear statement of what the agent can and cannot do: docs/CAPABILITIES.md.


Try it in 2 minutes (no Zoho account needed)

git clone https://github.com/vinamrasangal/zoho-inventory-mcp.git
cd zoho-inventory-mcp
make install     # creates .venv and installs the package with dev tools
make demo        # mock Zoho + MCP server over stdio + scripted merchant conversation
Zoho Inventory MCP connector — demo  (mock Zoho at http://127.0.0.1:56653)
MCP server exposes 11 read-only tools: connection_status, list_items, search_items, get_item, ...

Merchant: What do I need to reorder this week?
  → get_low_stock_items({"limit": 5})
  ✓ 6 ms
  Agent: 5 most urgent of the low-stock items (scanned 36):
     • Assam Breakfast Tea 250g         available    16   reorder at 40
     • Chai Lovers Gift Box             available     8   reorder at 30
     • Jaggery Powder 500g              available     5   reorder at 25
     • A2 Ghee 500ml                    available     2   reorder at 15
     • Kesar Saffron 5g                 available     0   reorder at 10

Merchant: What has Chaayos ordered recently, and is anything still open?
  → search_customers({"query": "Chaayos"})
  → list_sales_orders({"customer_id": "230000000100001", "per_page": 5})
  Agent: Chaayos Retail LLP has 5 recent orders; 3 still open. Outstanding receivable: ₹15,400.

Resilience: Zoho will now answer the next call with 429 Too Many Requests, then 503.
Merchant: Find our masala products.
  → search_items({"query": "masala", "per_page": 3})
  ✓ 1195 ms
  Agent: Found 3+ items (connector retried transparently): Biryani Masala 100g, Garam Masala 100g, ...

Guardrails: errors come back with a next step the agent can act on.
Merchant: Look up item 12345.
  → get_item({"item_id": "12345"})
  ✗ error: Item does not exist. Next step: Check the identifier; use a search tool to find the right ID before retrying.

Use it from an agent (Cursor / Claude Desktop) against the mock

make mock                                   # terminal 1: mock Zoho on :8800

Copy examples/mcp.mock.json into your MCP client config (Cursor: ~/.cursor/mcp.json; Claude Desktop: claude_desktop_config.json), fix the absolute path, and ask "Which products are below their reorder level?"

Call a tool from the shell

cp .env.example .env    # then uncomment the mock block at the bottom
zoho-inventory-mcp call search_items '{"query": "chai"}'
zoho-inventory-mcp call get_sales_order '{"salesorder_number": "SO-00042"}'

Related MCP server: HighLevel MCP Server

Connect a real Zoho Inventory organization

cp .env.example .env                      # add ZOHO_CLIENT_ID / ZOHO_CLIENT_SECRET / ZOHO_DATA_CENTER
zoho-inventory-mcp auth login             # browser consent → tokens saved (0600)
zoho-inventory-mcp orgs                   # pick your organization ID → ZOHO_ORGANIZATION_ID in .env
zoho-inventory-mcp auth status            # verify: org, scopes, token expiry, remaining quota
zoho-inventory-mcp serve                  # stdio MCP server (use examples/mcp.json in your host)

Step-by-step client registration, the Self Client (headless) flow and the token lifecycle are covered in docs/AUTH.md.


Tools

Tool

Purpose

Key inputs

connection_status

Connected? Which org? Token expiry, remaining rate-limit and quota

–

list_items

Browse the catalogue with price and stock

status, sort_by, page, per_page

search_items

Find items by name, SKU or description

query

get_item

Full item detail with per-warehouse stock

item_id or sku

get_low_stock_items

Items at or below reorder level, most urgent first

limit

list_sales_orders

Newest-first orders filtered by status, customer, date range

status, customer_id, date_from, date_to

search_sales_orders

Find orders by number, reference or customer name

query

get_sales_order

Line items, totals, invoice / payment / shipping status

salesorder_id or salesorder_number

list_customers

Browse active customers

page, per_page

search_customers

Find customers by name, company, email or phone

query

get_customer

Contact details, addresses, GSTIN, outstanding receivable

customer_id

The full MCP specification (descriptions, JSON Schemas for inputs and outputs, annotations, server instructions) is generated from code into docs/tool-spec.json. CI fails if it drifts from the code.

Rate limiting in one paragraph

Zoho allows roughly 100 requests per minute per organization, a handful of concurrent calls, and a daily quota that is shared with the merchant's other integrations. The connector enforces all three on the client side: a sliding 60-second window, a concurrency semaphore, and an optional ZOHO_DAILY_REQUEST_BUDGET. It also reads Zoho's X-Rate-Limit-Remaining header. If a 429 still arrives, every in-flight call cools down together, honouring Retry-After. 5xx and network errors use exponential backoff with full jitter. The tests check that a correctly configured connector sends zero 429s, and that a misconfigured one recovers. Details are in docs/ARCHITECTURE.md.

Configuration

All settings are environment variables (or .env). The common ones:

Variable

Default

Notes

ZOHO_CLIENT_ID / ZOHO_CLIENT_SECRET

–

From the Zoho API Console

ZOHO_DATA_CENTER

com

in, eu, com.au, jp, ca, sa, com.cn

ZOHO_ORGANIZATION_ID

–

Run zoho-inventory-mcp orgs to find it

ZOHO_REFRESH_TOKEN

–

Headless bootstrap (Self Client)

ZOHO_RATE_LIMIT_PER_MINUTE

100

Lower it if other integrations share the org

ZOHO_MAX_CONCURRENCY

5

Zoho's limit on the lowest plans

ZOHO_DAILY_REQUEST_BUDGET

unset

Hard cap on this connector's share of the daily quota

ZOHO_MAX_RETRIES

4

For 429 / 5xx / network errors

ZOHO_REDACT_PII

false

Mask customer email, phone and addresses

The full list is in config.py.

Project layout

src/zoho_inventory_mcp/
  server.py        MCP tools: schemas, descriptions, annotations, error → isError
  service.py       agent-friendly operations → Zoho queries; PII redaction
  client.py        HTTP: auth header, org scoping, retries/backoff, 401 refresh, pagination
  rate_limit.py    sliding window + concurrency + daily budget + cooldown
  auth/            OAuth manager, localhost login flow, token store
  models.py        compact, typed response models
  cli.py           auth login|exchange|status|logout, orgs, serve, call, export-spec
src/mock_zoho/     Starlette mock of Zoho Accounts + Inventory API (OAuth, scopes, 429s, failure injection)
tests/             45 tests: OAuth, resilience, rate limiter, tools over MCP
scripts/demo.py    end-to-end demo over stdio (also run in CI)
docs/              CAPABILITIES, AUTH, ARCHITECTURE, tool-spec.json

Development

make test        # pytest
make lint        # ruff check + format check
make spec        # regenerate docs/tool-spec.json

Assumptions & limitations

  • Built and tested against the mock because no live Zoho organization was available during development. The handful of API behaviours that should be confirmed on a real organization are listed in CAPABILITIES.md → Assumptions.

  • Read-only by design. Invoices, shipments and purchase orders are out of scope for v1.

  • Single tenant: one Zoho organization per server process. The streamable-http transport has no built-in auth, so keep it on a private network or use stdio.

  • The roadmap (writes with human approval, multi-tenant token vault, webhooks) is in CAPABILITIES.md → Roadmap.

License

MIT

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    Enables AI agents to manage multiple HighLevel CRM sub-accounts through a single OAuth-based MCP server, providing read-only access to contacts, conversations, opportunities, calendars, payments, blogs, emails, and social media.
    -
  • A
    license
    A
    quality
    C
    maintenance
    A read-only MCP server that lets AI assistants answer Shopify store operations questions via tools like get_shop, list_products, get_product, and list_orders.
    4
    MIT