store-ops-mcp
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., "@store-ops-mcpcheck inventory and sales for store STORE-001"
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.
store-ops-mcp
A TypeScript Model Context Protocol server built on the
official SDK (@modelcontextprotocol/sdk). It exposes two store-operations tools backed by
in-memory mock data (no database required):
Tool | Purpose |
| Consolidated read — inventory levels and sales velocity for a store in one call, plus days-of-supply, low-stock flags, and reorder suggestions. |
| Places a mock restock order for one or more SKUs, groups lines into purchase orders by supplier, and returns a costed confirmation. |
| Check-and-replenish workflow — for one SKU across N stores, compares on-hand vs. last 24h POS, computes the shortfall gap, and auto-raises an order at every store whose gap exceeds a threshold (default 6). |
Design choices & tradeoffs
Each choice optimizes for an agent doing a buyer's job well, not for a general-purpose API. The cost of each is stated plainly.
1. One combined tool instead of mirroring StoreLink's separate endpoints. Inventory and sales come back together, already compared.
You get: the agent asks one question and gets an answer it can act on — fewer steps, less to misread, lower chance of a wrong subtraction.
You give up: generality. Someone who wanted only raw inventory gets a bit more than they asked for.
2. The server does the reorder math, not the agent. The "reorder when the gap exceeds 6" rule lives in code.
You get: the same correct, explainable decision every time — the model can't fumble the arithmetic.
You give up: flexibility — the threshold is a sensible default in the server, not chosen per call (though it can be overridden).
3. Tools return a short confirmation, not the raw system response. An order returns an id, status, and totals.
You get: the agent sees just enough to confirm success and report back.
You give up: the full underlying response, which a power user might occasionally want.
4. A deliberately small toolset — and no destructive tools. No raw database access, no delete, no "edit anything" tool.
You get: a surface that's safe to hand an autonomous agent and easy to reason about.
You give up: the ability to do arbitrary operations through this server (by design).
5. Mock data instead of a live StoreLink connection.
You get: anyone can clone and run it in seconds — no credentials, no network.
You give up: real integration, which wasn't what this exercise was testing.
6. Keys read fresh on every request; missing keys fail safely.
You get: weekly key rotation "just works" with no restart, and an unknown store gets a clear, safe refusal instead of a crash.
You give up: a negligible re-read on each call.
7. Two plain-text log files — one for the buyer, one for engineers.
You get: each reader gets a log written in their language, with zero extra infrastructure.
You give up: a searchable dashboard out of the box (the structured log is ready to feed one later).
Related MCP server: Sales and Stock Analysis MCP Server
Setup
npm install
npm run build # compiles src/ -> dist/Run
npm start # node dist/index.js (speaks MCP over stdio)Docker / deployment
A production multi-stage Dockerfile builds a minimal, non-root image:
docker build -t store-ops-mcp:1.0.0 .
docker run -i --rm \
-e STORE_KEY_47=sk_live_xxx \
-v store-ops-logs:/var/log/store-ops \
store-ops-mcp:1.0.0-i is required — the server speaks MCP over stdio. See DEPLOYMENT.md for running
entirely inside Korral's private cloud with full data residency (air-gap posture, secrets,
log volumes, Kubernetes manifest).
The server communicates over stdio, the standard transport for local MCP servers. It prints a banner to stderr (stdout is reserved for the JSON-RPC protocol stream).
Smoke test
A tiny MCP client is included that spawns the server, lists the tools, and calls both:
node scripts/smoke-test.mjsUse it from an MCP client
Add it to a client's MCP config (e.g. Claude Desktop's claude_desktop_config.json):
{
"mcpServers": {
"store-ops": {
"command": "node",
"args": ["E:\\temp\\duvo\\dist\\index.js"]
}
}
}Tool reference
get_store_inventory_and_sales
Param | Type | Required | Description |
| string | yes |
|
| string | no | Filter, e.g. |
| boolean | no | Return only items at/below their reorder point |
Returns store totals plus a per-SKU breakdown with inventory, sales
(incl. revenue30d, daysOfSupply), and replenishment (suggested qty + supplier/lead time).
create_replenishment_order
Param | Type | Required | Description |
| string | yes | Target store |
| array | yes |
|
| string | no | Free-text note on the order |
The order is validated all-or-nothing (unknown SKUs reject the whole order), grouped into one
purchase order per supplier, costed at wholesale unitCost, and the affected products'
onOrder quantities are updated so subsequent inventory reads reflect the pending order.
evaluate_replenishment
Param | Type | Required | Description |
| string | yes | Product to evaluate, e.g. |
| string[] | yes | Stores to check, e.g. |
| number | no | Order only when |
| boolean | no | Evaluate/recommend without placing orders |
Decision rule: gap = unitsSoldLast24h - onHand. When gap > gapThreshold the store
is breached and an order for max(reorderQuantity, gap) units is raised; otherwise no action.
This is the logic behind the worked example:
SKU 8847291 (Madeta butter 250g) is running empty at stores 47 and 102. Check on-hand vs. last 24h of POS for both, and raise a replenishment order for any store where the gap exceeds 6 units.
node scripts/task-scenario.mjsResult: Store 47 (on-hand 4, sold 18 → gap 14 > 6) → order RO-47-0001 for 48 units;
Store 102 (on-hand 5, sold 9 → gap 4 ≤ 6) → no action.
Credentials
Every store is gated by a per-store API key read from the environment. The variable name is
STORE_KEY_<STOREID> — the storeId upper-cased with non-alphanumerics collapsed to _:
Store | Env var |
|
|
|
|
|
|
Behaviour (implemented in src/index.ts → validateStoreCredential):
Fail safe — a missing or blank key never throws or crashes the server. Single-store tools return an
isErrorresult (Access denied. Missing credential …); the multi-storeevaluate_replenishmentmarks just that storecredential_invalidand continues with the rest. The raw key is never logged or returned — only a short SHA-256 fingerprint is used internally.Mid-flight changes — the variable is re-read on every call (never cached at startup), so rotating or removing a key takes effect on the next request with no restart. A changed key is detected via fingerprint and logged as
credential_rotated(audit + debug).
# example
export STORE_KEY_47=sk_live_xxx
export STORE_KEY_102=sk_live_yyy
node dist/index.jsDemonstrate the full lifecycle (missing → present → rotated → removed → blank):
node scripts/credential-test.mjsDual logging
Every tool call writes to two append-only logs (see src/logger.ts). The
location defaults to the process working directory; override with STORE_OPS_LOG_DIR.
buyer_audit.log— plain, simple English. One readable line per business event for a buyer/ops reader:[2026-06-30T19:09:55.382Z] Store 47 (Praha Vinohrady): Madeta butter 250g running low — 4 on hand vs 18 sold in last 24h (gap 14 over 6). Raised order RO-47-0001 for 48 unit(s). [2026-06-30T19:09:55.414Z] Store 102 (Brno Kralovo Pole): Madeta butter 250g stock OK — 5 on hand vs 9 sold in last 24h (gap 4 within threshold 6). No order needed.fde_debug.log— structured JSONL (one JSON object per line) with full technical detail for a Forward Deployed Engineer:{"ts":"2026-06-30T19:09:55.365Z","event":"replenishment_evaluation","storeId":"47","sku":"8847291","onHand":4,"unitsSoldLast24h":18,"gap":14,"gapThreshold":6,"breached":true,"action":"order_placed","orderId":"RO-47-0001","quantity":48}
stdout is never used for logging — it carries the MCP JSON-RPC stream.
Example traces are committed under samples/ (the live *.log files are
gitignored — they're generated artifacts and hold business data in production).
Mock data
Defined in src/data.ts: two stores, several SKUs each, three suppliers with
lead times. Edit that file to change the catalog.
Project layout
src/index.ts MCP server + tool definitions
src/data.ts mock stores / products / suppliers
scripts/smoke-test.mjs end-to-end client test
dist/ compiled output (after npm run build)Available Tools
3 toolscreate_replenishment_orderCreate Replenishment OrderA
Place a replenishment (restock) order for one or more SKUs at a store. Validates each SKU against the store, groups lines by supplier into purchase orders, computes line/PO/order totals, and updates on-order quantities. Returns a confirmation with per-PO detail.
| Name | Required | Description | Default |
|---|---|---|---|
| lines | Yes | One or more order lines (SKU + quantity). | |
| notes | No | Optional note attached to the order. | |
| storeId | Yes | Store identifier, e.g. one of: STORE-001, STORE-002, 47, 102 |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Without annotations, the description carries the burden and does well: it discloses validation, grouping by supplier, computing totals, and updating on-order quantities. This covers key mutation behaviors, though it omits details on error handling or rollback.
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 description is a single paragraph of three sentences, front-loading the purpose. Every sentence provides unique information without repetition, achieving high density of useful content.
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 creation tool with no output schema, the description covers core actions and mentions a 'confirmation with per-PO detail'. However, it lacks specifics on return format (e.g., order ID), error scenarios, prerequisites (store/SKU existence), and rate limits, leaving moderate 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 coverage is 100%, so the baseline is 3. The description adds context like 'validates each SKU against the store' and 'groups lines by supplier', which are behavioral rather than parameter-specific. It does not enhance individual parameter meaning beyond 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?
The description clearly states the verb 'Place' and resource 'replenishment (restock) order for one or more SKUs at a store'. It also details specific actions like validation, grouping, and updating, making it distinct from sibling tools like evaluate_replenishment.
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 implies when to use this tool (to place a restock order) and distinguishes it from siblings by focusing on creation vs. evaluation/inventory retrieval. However, it does not explicitly state when not to use or provide alternative scenarios.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
evaluate_replenishmentEvaluate & Replenish Low StockA
For a single SKU across one or more stores, compare on-hand stock against the last 24 hours of POS sales, compute the shortfall gap (units sold in last 24h minus units on hand), and automatically raise a replenishment order at every store whose gap exceeds a threshold (default 6 units). Returns the per-store evaluation plus any orders created. Set dryRun=true to evaluate without placing orders.
| Name | Required | Description | Default |
|---|---|---|---|
| sku | Yes | Product SKU to evaluate, e.g. '8847291'. | |
| dryRun | No | If true, evaluate and recommend but do not place orders. | |
| storeIds | Yes | Stores to check, e.g. ['47', '102']. | |
| gapThreshold | No | Raise an order only when (last24h sales - on-hand) exceeds this. Default 6. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description bears full responsibility for behavioral disclosure. It explains the evaluation logic, conditional order placement, default threshold, and safety of dryRun mode. It does not mention reversibility or side effects of placed orders, but the core behavior is transparent.
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 description is concise: four sentences covering purpose, logic, output, and dryRun. It is front-loaded with the key verb and resource, and every sentence adds value without redundancy.
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?
Given the tool's moderate complexity (evaluation + order creation, 4 parameters, no output schema), the description is remarkably complete. It explains inputs, process, conditional behavior, default, and dryRun. The sibling tools provide further context for alternative actions.
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 100%, so baseline is 3. The description adds significant meaning beyond the schema by explaining the shortfall calculation (gap = last24h sales - on-hand), the role of gapThreshold, and dryRun as a safety toggle. This provides the agent with a holistic understanding of how parameters interact.
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 clearly defines the tool's purpose: evaluate a single SKU across one or more stores, compute shortfall based on last 24h sales vs. on-hand, and automatically raise replenishment orders. It distinguishes itself from siblings by specifying the combined evaluation and ordering action.
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 explains when to use the tool (for evaluating low stock and ordering), mentions a default threshold, and highlights the dryRun option for safe testing. It does not explicitly state when not to use it, but the context is clear enough.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_store_inventory_and_salesGet Store Inventory & SalesA
Consolidated view of inventory levels and sales performance for a store. Returns per-SKU on-hand/on-order stock, 30-day sales velocity and revenue, days-of-supply, low-stock flags, and suggested reorder quantities. Optionally filter by category or show only low-stock items.
| Name | Required | Description | Default |
|---|---|---|---|
| storeId | Yes | Store identifier, e.g. one of: STORE-001, STORE-002, 47, 102 | |
| category | No | Optional category filter, e.g. 'Dairy', 'Beverages', 'Household'. | |
| lowStockOnly | No | If true, return only items at or below their reorder point. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries full burden. It clearly describes the output but does not explicitly state that the tool is read-only or has no side effects. However, the verb 'get' and the nature of the output (inventory/sales data) strongly imply it is non-destructive.
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 sentences with no wasted words. The first sentence states purpose and main outputs, the second sentence specifies options. Information is front-loaded and every sentence adds value.
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?
Given that there is no output schema, the description compensates by listing six specific output fields (on-hand/on-order stock, 30-day sales velocity, revenue, days-of-supply, low-stock flags, suggested reorders). Together with parameter details, this provides a complete picture for an agent to understand what data the tool returns.
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 input schema has 100% description coverage for three parameters. The description adds meaning by explaining the optional parameters: 'filter by category or show only low-stock items'. This goes beyond the schema descriptions, which are already clear.
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 clearly states the tool provides a consolidated view of inventory levels and sales performance, listing specific output fields (per-SKU stock, sales velocity, revenue, etc.) and optional filters. This distinguishes it from siblings like create_replenishment_order and evaluate_replenishment which are action-oriented.
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 implies this tool is for data retrieval to inform replenishment decisions, and the sibling tool names ('create_replenishment_order', 'evaluate_replenishment') reinforce the context. However, it lacks explicit guidance on when to use this vs. alternatives or when not to use it.
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.
3 tool updates
v1.0.0- First observed
create_replenishment_order - First observed
evaluate_replenishment - First observed
get_store_inventory_and_sales
TDQS
Scored across 3 tools
Each tool has a distinct purpose: viewing inventory/sales, evaluating replenishment needs, and creating orders. No overlap in functionality.
All tool names follow a consistent verb_noun pattern (create_, evaluate_, get_) and use snake_case throughout.
Three tools is a minimal but focused set covering the core workflow of viewing inventory, evaluating needs, and placing orders. It's slightly thin but well-scoped.
Covers the primary operations (view, evaluate, create) but lacks order management (list, update, cancel) and supplier handling, which are notable gaps.
Maintenance
Related MCP Connectors
Run storefronts, listings, orders, content, fulfillment, and analytics through AI.
AI shopping gateway for product search, inventory, carts, and merchant-hosted checkout.
Inventory management for small organizations: search, assign, report, order, set up by chat.
Ask questions in plain language, get answers from your business database. No SQL required.
Related MCP Servers
- FlicenseNot gradedqualityCmaintenanceEnables identification of BSN SKU/material and real-time inventory availability through natural language queries and vector search.-
- FlicenseNot gradedqualityCmaintenanceEnables querying sales data, identifying out-of-stock products, viewing top sellers, and receiving restock suggestions through natural language.-
- FlicenseBqualityBmaintenanceEnables merchants and customers to interact with the Shoppingate AI Platform, including product searches, inventory management, order tracking, promotions, and personalized recommendations via natural language.14-
- AlicenseNot gradedqualityBmaintenanceEnables product discovery, session-scoped carts, and confirmation-gated checkout through natural language, with deterministic routing and safety features.9 npmISC