Project Tango
Project Tango is a local-first MCP server for e-commerce data: browse products, analyze sales, manage inventory, draft copy, place simulated orders, and reset state.
list_all_products: browse/filter/search the catalog by category, price range, or free-text.get_low_stock_alerts: scan inventory for low/critical stock, optionally by category.analyze_sales_metrics: compute revenue, AOV, top sellers, status breakdown, and daily trend, optionally scoped to a category.find_orders: look up orders by exact ID or customer-name substring, with enriched line items and optional limit.smart_restock_predictor: rank low-stock items by days of cover and recommend reorder quantities.draft_product_copy: generate marketing copy and SEO tags for a SKU.simulate_order_placement: place a simulated order, validate/decrement stock atomically, and return a receipt.reset_demo_state: discard simulated orders and restore the seed catalog.Expose a
weekly_inventory_reviewprompt and atango://catalogJSON resource.Persist state locally via SQLite (or JSON), survive restarts, and swap mock data for live Shopify/Stripe through a
DataProviderinterface.
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., "@Project Tangoshow me products with low stock"
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.
Project Tango
A local-first Model Context Protocol server that gives LLM agents — Claude Desktop, Cursor, VS Code, or any MCP-compatible client — instant, structured access to e-commerce data: products, inventory, orders, and sales analytics.
Project Tango ships with a realistic mock dataset so it works in under a minute with zero configuration, and it's built around a clean DataProvider interface so you can swap the mock engine for live Shopify/Stripe APIs without touching a single tool definition.
Runs entirely on your machine over stdio — no server to deploy, no database to host.
$0 infrastructure cost.
State survives a restart — writes land in a local SQLite database, not in memory that evaporates when the MCP client relaunches the process.
Production-ready TypeScript, strict mode, fully typed domain model.
Release history, including a divergent v2.0.0 lineage that was never merged
into main (its trie search is ported here; see
CHANGELOG.md).
What's inside
Tool | What it does |
| Browse the catalog, filtered by category, price range, or free-text search — results ranked so a product whose own name, SKU, category or tag matches ranks above one that merely mentions the term |
| Scans inventory and flags |
| Gross revenue, AOV, top sellers, order-status breakdown, and a daily trend with a recent-vs-previous comparison — all optionally scoped to one category |
| Ranks low-stock items by days of cover and recommends an exact reorder quantity for each, optionally within one category |
| Generates marketing copy + SEO tags for a given SKU |
| Looks up an order by id or a customer by name, with lines enriched by product name and price; uncapped by default, bounded with an optional |
| Places a simulated order, validates stock, decrements inventory |
| Discards simulated orders and restores the seed catalog |
Beyond tools, the server exposes a weekly_inventory_review prompt that
sequences the review (alerts → restock plan → trend) with its reporting format,
and a tango://catalog resource that serves the product catalog as JSON for
clients that read resources rather than call tools. The prompt takes an optional
category, and the scoping is real: every step the prompt sequences accepts the
category itself, so a scoped run genuinely returns category-scoped numbers
rather than catalog-wide ones wearing a category heading.
Read tools answer "nothing matched" the same way everywhere — a successful
response with count: 0 and an empty list. Only a malformed call (no usable
filter at all, an unknown SKU) is a tool error. Responses echo the filters
actually applied, so a blank argument reads back as null instead of as a
filter that matched everything or nothing.
find_orders is deliberately uncapped by default and has no pagination.
customer_name is a substring match, so a one-letter query matches most of the
dataset — on the bundled seed data, "a" matches 130 of the 142 orders, about 46 KB of JSON.
Against a live provider those figures differ; what does not change is that
nothing is dropped. Truncating would remove orders from a response that reports
count and claims to enumerate its matches, so the default narrows nothing and
callers narrow the filter instead (or pass an order_id for a single order).
Callers who want a bound ask for one with limit — and totalMatches always
reports the full match count, so a capped answer admits exactly how much it
withheld. A test pins the invariant — count equals the number of orders
actually delivered, and totalMatches is never smaller than it — rather than
any particular result size, so it holds at any dataset size.
Every tool declares an outputSchema and returns typed structuredContent, so
clients validate the response instead of re-parsing JSON — and the shape is
visible in tools/list before a call is made. A compact JSON rendering is
returned alongside for clients and models that read the text block. The schemas
in src/schemas.ts are the single source of truth: the analytics modules derive
their return types from them, so a response shape cannot drift from the
implementation without a compile error.
Related MCP server: Saleor MCP Server
Prerequisites
Node.js 22.5 or later (
node -vto check) — the floor isnode:sqlite, the built-in database the server stores its state in. On an older runtime the server refuses to start and says why, rather than silently running without persistence; see Runtime floor.npm (ships with Node)
Quickstart
# 1. Clone the repository
git clone https://github.com/CoderGamerUnknow/Project-Tango.git
cd Project-Tango
# 2. Install dependencies
npm install
# 3. Run it locally
npm startnpm start runs tsx src/index.ts directly — no build step needed for local development. The server communicates over stdio, so running it directly in a terminal will just sit there waiting for a JSON-RPC client (that's expected — it's designed to be launched by an MCP client, not used interactively).
To produce a compiled build (used by the client configs below):
npm run build # emits dist/index.js
npm run inspect # optional: open the MCP Inspector to poke at tools by handTesting
npm test # typecheck, then the suite
npm run lint # type-aware ESLint over source and suites
npm run test:coverage # the suite under coverage, with minimum thresholds
npm run verify # typecheck + lint + coverage + build, in one shot287 tests, no test framework to install — Node's built-in test runner drives
tsx. The
suites are typechecked before they run (pretest → npm run typecheck), which
covers them as well as the source; previously only the source was checked, so a
broken test reached the runner and failed as a runtime error instead of a
compile error. tsconfig.test.json is what makes that possible — the build
config has to exclude *.test.ts so they never reach dist/.
Coverage is a gate, not a report: npm run test:coverage fails the run below
98% line / 94% branch / 96% function coverage, so a new branch without a
test breaks the build instead of hiding. The lint gate is type-aware
(typescript-eslint with type information — floating promises, unsafe any
propagation) with one documented exception for test payloads, where any is
the honest type of parsed JSON. GitHub Actions
(.github/workflows/ci.yml) runs typecheck, lint, the coverage-floored suite,
a check that this very test count matches the runner, and the build on every
push.
The suite runs in five layers:
Unit (
src/catalog.test.ts,src/orderAnalytics.test.ts,src/restock.test.ts,src/productCopy.test.ts,src/storage.test.ts,src/sqliteStore.test.ts,src/mockData.test.ts,src/reviewPrompt.test.ts) pins the business logic, the state store, the search index, the provider, and the rendered review prompt directly: velocity math, lookback-window resolution, threshold boundaries, order-line aggregation, revenue attribution, order drill-down, category scoping, sales trend, copy generation, persistence atomicity/recovery, transaction rollback, and read isolation (MockDataProviderhands out copies, never live references).src/sqliteStore.test.tsadditionally opens real databases: it proves the store waits out another process's lock instead of falling back, that a rolled-back transaction leaves the store usable, and that search ranking never drops a substring match. Each unit suite pairs with the module it covers, so the split is visible in the tests too.End-to-end (
src/tools.test.ts) drives a single long-lived server over stdio with the MCP SDK's own client, covering tool registration, declared output schemas, structured responses, the prompt and resource surface, scoped calls on every tool, and the write-path guarantees (no partial writes, unique order ids, inventory never negative,transact()honoured under concurrency).Lifecycle (
src/persistence.test.ts) restarts real server processes to prove state survives, seed rows reconcile correctly, corrupt files recover, andreset_demo_stateworks — including that a rejected order does not poison the transaction queue for later callers, that two server processes racing on one data directory both keep their writes, and that ten concurrent orders against 42 units of stock accept exactly eight.In-process seam (
src/server.test.ts) builds the entire MCP surface withcreateServer(provider)against a stubDataProviderover the SDK's in-memory transport — the proof that swapping providers needs no process and no module rewiring.Bootstrap (
src/bootstrap.test.ts) launchessrc/index.tsas the real child process a user launches, because it is the one module no test can import: it takes over stdout and callsprocess.exit. It covers the runtime floor end to end — that a too-old runtime exits non-zero with an explanation, answers nothing on stdout, and does not even create its data directory, while both documented escapes (JSON backend,PROJECT_TANGO_PERSIST=0) start normally.Docs (
src/docs.test.ts) reads the README and changelog as text and pins their claims — dataset figures, structure tree, tool names, release headings, release dates, and the divergentv2.0.0lineage — to the code, the data and the git tags they describe, so documentation cannot rot quietly.
Every server the tests launch is pinned to a temp data directory, so running the
suite never touches your real ~/.project-tango catalog.
Several tests are explicit regressions for bugs this server previously shipped —
duplicate order lines driving inventory negative, colliding order ids, a
Math.max(NaN, …) seed that silently broke lookback anchoring, concurrent
orders overselling stock from -7, saved state silently deleting seed products,
unchecked restored records crashing the catalog, reads handing out live
references whose mutation bypassed the persistence counter, a throwing
transaction committing the half-applied state it was supposed to discard, a
sales lookback window that measured 31 days of demand and divided by 30, and
non-finite numbers in a restored state file failing every analytics tool's output
validation.
State and persistence
simulate_order_placement is a write tool, so its effects have to outlive the
process — MCP clients relaunch the server routinely, and an agent that places an
order in one session then asks about inventory in the next would otherwise be
told about a catalog state that no longer exists.
State is written to state.db — a SQLite database — after every mutation and
restored on startup.
Variable | Effect |
| Directory holding the state database. Defaults to |
| Disable persistence entirely — the original in-memory behaviour, for throwaway or CI runs. |
| Use the older whole-snapshot JSON file instead of SQLite. Useful on a runtime without |
Delete state.db to reset back to the seed dataset. Saved state is reconciled
against the seed catalog rather than replacing it: products present in the state
file win (they carry the real stock history), while seed products missing from
it are re-added, so editing the catalog still takes effect. The server logs what
it restored on startup.
An existing state.json from an earlier version is imported automatically on
first run — validated record by record, exactly as the JSON store did, so a
malformed record is dropped rather than becoming a runtime failure — and the old
file is kept as state.json.migrated.
Upgrading from 3.1.0. That release shipped two data-loss defects, and if you hit either of them your stored state may hold fewer products than the seed catalog: the server would list all thirteen and then refuse to sell one of them, committing the shortfall so it survived every restart. 3.1.1 repairs this on its own — starting it re-adds the missing seed products, and the first write that follows saves the repaired catalog back, so there is no manual step. Upgrade to 3.1.2 or later and restart. Nothing you placed is lost: orders recorded against the missing products are still in the database and resolve again once the products are back. See the 3.1.0 release notes.
The store is deliberately forgiving, because this process is a background child of someone else's app: saves are atomic (one transaction for the whole snapshot), an unreadable, corrupt, wrong-shape or wrong-version store degrades to the seed dataset with a warning on stderr rather than taking the tools down, and a read-only data directory disables persistence with a warning instead of crashing.
Concurrency. Order placement wraps its read-validate-write in a SQLite
BEGIN IMMEDIATE transaction, which takes the database's write lock before the
first read. Two server processes sharing one data directory therefore serialise:
each validates against the state as of the moment it acquired the lock, so one
cannot pass a stock check against a snapshot the other has already moved past.
The suite drives two real server processes against one directory to pin this —
both orders survive, stock reflects both, and ten racing attempts at 5 units
against a stock of 42 fill exactly eight orders rather than driving inventory
negative. The lock is released on commit, rollback, or process death.
Reading. A server keeps its catalog in memory, and an MCP client keeps a
server alive for a whole conversation — so a second window could write while this
one reads. Before each read the server compares a cheap change token
(PRAGMA data_version, which moves for other connections' commits and not for
its own) and reloads only when another process has actually committed. Staying
current therefore costs one query per read rather than a full reload, and a
server that never wrote anything still sees what everyone else did. A read never
happens mid-transaction, so a reload can never discard a write that has not
committed yet.
The token is a required part of the StateStore contract, not an optional extra.
A backend that genuinely cannot detect another writer has to say so with
stableToken(reason) rather than omit the member, so "this one goes stale" is a
decision someone wrote down instead of a gap nobody noticed. The suite holds two
real server processes against one data directory through a soak — 40 commits
spread over four products while the reader serves hundreds of interleaved
list_all_products calls — and asserts the properties that matter under load
rather than on a single sample: no read ever trails a committed write by more
than one commit, the reader becomes current within three reads of the writer going
quiet, it follows the stream rather than jumping once at the end, and it never
serves a catalog mid-write or reports stock moving backwards. The check itself is
pinned by a performance guard: it must stay at least 20x cheaper than the reload
it avoids (measured ~72x on the shipped dataset).
PROJECT_TANGO_STORE=json keeps the previous whole-snapshot backend available,
and its guarantee is deliberately narrower: it publishes one process's complete
snapshot (never a torn file) but is still last-writer-wins across processes,
because load()/save() cannot be made atomic between two independent copies.
Runtime floor
Most failures to persist are environmental — an unwritable directory, a full disk, a database another process is holding — and those degrade to a warning on stderr, because a warning is recoverable where a dead server is not.
One is not: a runtime with no node:sqlite. That will still be true tomorrow,
and a server that starts anyway accepts orders and discards every one of them at
exit, reporting it on a stderr line the launching MCP client throws away. It is
the single worst thing a store whose headline feature is "state survives a
restart" can do, and it is silent. So the server checks before it connects and
refuses to start, naming the fix:
$ npx project-tango
Project Tango cannot start on Node 18.20.4.
This runtime has no built-in SQLite, which needs Node 22.5.0 or later. The durable
store this server is built around is therefore unavailable, and starting anyway
would accept orders and discard every one of them when the process exits — silently,
because the fallback warning goes to a stderr line the launching MCP client throws away.
…Either upgrade Node, or set PROJECT_TANGO_STORE=json to accept the narrower
durability guarantee above, or set PROJECT_TANGO_PERSIST=0 to say you meant to
run without persistence. engines.node is >=22.5.0 to match, but npm only
warns on an engine mismatch by default, so this check is the one that actually
holds the line. src/storage.test.ts pins all three escape hatches.
Connecting Project Tango to an MCP client
Both configs below assume you've run npm run build and are pointing at the absolute path of your local clone.
A) Claude Desktop
Edit your claude_desktop_config.json (Claude menu → Settings → Developer → Edit Config) and add an entry under mcpServers:
{
"mcpServers": {
"project-tango": {
"command": "node",
"args": ["/absolute/path/to/project-tango/dist/index.js"]
}
}
}Restart Claude Desktop. Project Tango's tools will appear in the tool picker (hammer icon) in your next conversation.
Prefer not to build first? You can point Claude Desktop at
tsxinstead:{ "mcpServers": { "project-tango": { "command": "npx", "args": ["tsx", "/absolute/path/to/project-tango/src/index.ts"] } } }
B) Cursor
In Cursor: Settings → MCP → Add new MCP Server, or edit .cursor/mcp.json in your project (or ~/.cursor/mcp.json globally):
{
"mcpServers": {
"project-tango": {
"command": "node",
"args": ["/absolute/path/to/project-tango/dist/index.js"]
}
}
}Cursor will list project-tango under Settings → MCP with a green dot once it connects successfully, and its tools become available to the agent in Composer/Chat.
Going live: swapping mock data for Shopify/Stripe
Every tool in src/server.ts is written against the DataProvider interface defined in src/types.ts — it never touches the mock arrays directly. To connect real data:
Create
src/shopifyDataProvider.ts(or similar) implementingDataProvider:export class ShopifyDataProvider implements DataProvider { async getProducts() { /* call Shopify Admin API */ } async getOrders() { /* call Shopify Admin API */ } async getProductBySku(sku: string) { /* ... */ } async updateProductInventory(id: string, newCount: number) { /* ... */ } async addOrder(order: Order) { /* ... */ } // Order placement reads stock, awaits, then writes. Without a transaction // an interleaved caller validates against a snapshot you have already moved // past, and oversells. Map this onto whatever your store offers. async transact<T>(fn: (p: DataProvider) => Promise<T>) { /* real transaction */ } // Optional. Omit it and `reset_demo_state` simply reports that the // provider does not support it — do NOT stub it with a destructive // no-op, or an agent will "reset" your live inventory. async reset() { /* throw or omit the method entirely */ } }In
src/index.ts, change one line:const dataProvider: DataProvider = new ShopifyDataProvider(/* credentials */);The whole surface is also constructible in-process as
createServer(provider)(src/server.ts) — which is how the test suite exercises the seam against stub data without spawning anything.Rebuild (
npm run build) — no tool logic changes required.
Security
Local-first by design. Project Tango runs as a child process on your own machine and speaks to its MCP client exclusively over stdio. There is no network listener, no exposed port, and no cloud component in the default configuration.
Zero external data exposure. With the default mock
DataProvider, no data ever leaves your machine — there are no outbound network calls anywhere in the tool logic.Explicit, validated inputs. Every tool parameter is validated at runtime with Zod schemas before any logic executes, rejecting malformed or out-of-range input before it reaches your data layer.
No silent partial writes.
simulate_order_placementvalidates stock for every line item before mutating any inventory — a failing item rejects the whole order rather than leaving data half-updated. The whole read-validate-write runs insideDataProvider.transact(), so concurrent calls cannot all pass a stock check against the same pre-write snapshot, and atomicity is a property of the data layer rather than of this server's wiring. If a provider method throws halfway through,transact()restores the pre-transaction state and skips the save, so neither memory nor the state file is left holding a half-applied order.Every write is reversible.
simulate_order_placementis irreversible within a session, so an agent exploring the catalog could otherwise permanently distort the numbers it reports back.reset_demo_statediscards simulated orders and restores the seed dataset.Bring your own credentials for live mode. When you implement a real
DataProvideragainst Shopify/Stripe, credentials should be loaded from environment variables (e.g. viaprocess.env) and never hard-coded — this template intentionally ships with no secrets or network calls of any kind.
Project structure
project-tango/
├── package.json
├── tsconfig.json
├── tsconfig.test.json
├── eslint.config.mjs # Type-aware lint gate (npm run lint)
├── .github/workflows/ci.yml # CI: typecheck, lint, coverage floor, build, docs drift
├── .github/workflows/release-artifact.yml # Packs, installs and smoke-tests the tarball, then attaches it to the release
├── src/
│ ├── types.ts # Domain types + DataProvider interface
│ ├── schemas.ts # Zod response schemas — the source of truth for shapes
│ ├── conventions.ts # Rules shared by several analytics modules (rounding, blank input)
│ ├── catalog.ts # Product filtering + low-stock alerts + search ranking
│ ├── productIndex.ts # Prefix index that ranks search results (ported from the v2.0.0 lineage)
│ ├── sqliteStore.ts # SQLite durable store with cross-process write transactions
│ ├── orderAnalytics.ts # Windowing, sales metrics, trend, order drill-down + buildOrder (order + stock writes)
│ ├── restock.ts # Restocking policy + demand-velocity planning
│ ├── productCopy.ts # Marketing copy + its per-tag voice tables
│ ├── toolNames.ts # The eight tool names, declared once
│ ├── responses.ts # jsonResult / errorResult wire envelopes
│ ├── reviewPrompt.ts # The weekly review prompt as a pure function
│ ├── server.ts # MCP surface: createServer(provider) — 8 tools, 1 prompt, 1 resource
│ ├── mockData.ts # MockDataProvider (read this to implement DataProvider)
│ ├── seedCatalog.ts # The 13-product starter catalog
│ ├── orderGenerator.ts # Deterministic seeded order history
│ ├── storage.ts # Durable state: store selection, atomic JSON store, recovery
│ ├── index.ts # Process bootstrap: picks the provider, connects stdio
│ ├── testHelpers.ts # Shared fixtures + stdio launcher for the suites
│ ├── testGlobalSetup.ts # Pins every test process to a throwaway data directory
│ └── *.test.ts # Unit, e2e, lifecycle, in-process seam and docs suites
├── CHANGELOG.md # Release history, pinned to the tags by src/docs.test.ts
└── README.mdThe split between the analytics modules and the MCP wiring is deliberate: every
tool's logic is a pure function over plain data, so it can be unit tested
without spawning a server, and the handlers stay readable as validate → fetch →
compute → wrap. server.ts owns registration only — it takes the DataProvider
as an argument (createServer(provider)), so the whole surface can be built
in-process against stub data, while index.ts is the thin bootstrap that picks
the real provider and connects stdio. The analytics layer is itself split by
concern — catalog, orders, restock, copy — because a single 750-line file
covering all four is none of them; conventions.ts holds only the rules more
than one of them follows, so a shared rule has exactly one owner instead of one
copy per module.
Releasing
The order matters more than it looks, because two of these steps are checked against each other and getting them backwards fails after the release is already public.
npm run release:check 3.1.3 # before you tag anythingPrepare. Bump
package.json,package-lock.json(npm install --package-lock-only) andSERVER_VERSIONinsrc/server.ts. Write the## [3.1.3] — YYYY-MM-DDchangelog section and its[3.1.3]:link definition.docs.test.tsrefuses a release whose heading has no tag and whose tag date is not the heading's date.Verify locally.
npm run verify— typecheck, lint, coverage, build.Commit, then tag the commit.
git commit -am "Release v3.1.3: ..." git tag -a v3.1.3 -m "Project Tango v3.1.3"Push the tag before the branch. This is the one that bites. A tag run checks out a detached HEAD and reads
main's tag history; if the branch has not landed,docs.test.tsdies onfatal: malformed object name mainandunknown revision vX.Y.Z. That is how the 3.1.0, 3.1.1 and 3.1.2 tag runs all went red while the same commits passed onmain.git push origin v3.1.3 # tag first git push origin main # then the branchWait for the tag run to go green before publishing. A release published over a red run is a published release nobody has verified, and it cannot be un-published. CI now runs
scripts/release-check.mjson tag pushes, so a mismatch fails there rather than in a bug report.Publish with notes generated from the changelog section (so the two cannot drift), and let
release-artifact.ymlattach the tarball. The artifact is built and installed and booted on the runner before upload — an asset uploaded from a contributor's machine has silently corrupted every file it touched on this project.Confirm the tarball is attached, then delete the temporary branch if you used one. CI also runs on Windows; both legs must be green.
scripts/release-check.mjs is the mechanical half of steps 1 and 5, and it is
what CI runs on a tag push.
License
MIT
Available Tools
8 toolsanalyze_sales_metricsAnalyze Sales MetricsA
Calculates gross revenue, average order value (AOV), the top-selling products by units sold, and a breakdown of orders by fulfillment status (pending / shipped / delivered), based on current order history. Figures cover all recorded orders; the 'period' field reports the actual date span so a stale dataset is visible. An optional category scopes every figure to products in that category: revenue, units and the trend count only lines of those products, an order counts toward the breakdown and AOV when it contains at least one such line, and the echoed 'filters' block reports the category actually applied.
| Name | Required | Description | Default |
|---|---|---|---|
| category | No | Restrict to a single category, e.g. 'tech', 'apparel', or 'home'. Case-insensitive. Omit to cover the whole catalog. |
Output Schema
| Name | Required | Description |
|---|---|---|
| trend | Yes | |
| period | Yes | |
| filters | Yes | |
| orderCount | Yes | |
| grossRevenue | Yes | |
| averageOrderValue | Yes | |
| topSellingProducts | Yes | |
| orderFulfillmentBreakdown | Yes |
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 that figures span all recorded orders, that the 'period' field exposes a stale dataset, and that an echoed 'filters' block reports the category actually applied. It omits any authorization, cost, or performance caveats, but the data-scope semantics are unusually well spelled out.
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?
It is dense but front-loads the computed metrics before the scoping caveats, and the second paragraph is reserved for the optional category semantics. Every sentence carries information, though the scoping clause is long enough to require re-reading.
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?
An output schema exists, so return values needn't be explained, and the description covers the behavioral scope thoroughly for a single-optional-param read tool. Only the missing when-to-use guidance against sibling tools keeps it from being fully complete.
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% and the single category param is already documented there, so the baseline would be 3. The description goes beyond the schema by defining exactly how the category scopes each metric (orders count toward AOV/breakdown only when they contain a matching line), which is genuine added meaning.
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 precise verb (calculates) plus the exact outputs: gross revenue, AOV, top-selling products by units, and an orders-by-fulfillment-status breakdown. This is clearly distinguishable from siblings that deal with products, orders, or stock levels rather than aggregate analytics.
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 an analytics/reporting use case and notes figures cover all recorded orders, but it never says when to reach for this over find_orders or the restock tools. Usage is inferable from the content but not stated as guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
draft_product_copyDraft Product CopyA
Looks up a product by SKU and generates structured, high-conversion marketing copy (headline, short and long description, key bullet points) plus SEO tags tailored to that product's category and tags.
| Name | Required | Description | Default |
|---|---|---|---|
| sku | Yes | The exact product SKU to generate marketing copy for, e.g. 'TCH-AB-001'. |
Output Schema
| Name | Required | Description |
|---|---|---|
| sku | Yes | |
| copy | Yes | |
| seoTags | Yes | |
| productId | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden. It usefully discloses the shape of the generated output and that the copy is tailored to the product's category and tags, and the verbs 'looks up' and 'draft' imply a non-destructive read/generate flow. However, it never states whether the draft is persisted, what happens if the SKU is unknown, or that generation may be slow/costly — real gaps for a mutation-adjacent tool with zero annotation coverage.
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?
A single well-formed sentence with the lookup-and-generate action front-loaded and the output list appended as a compact parenthetical. Every clause earns its place with 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 one-parameter tool with full schema coverage and an output schema (so return values need no explanation), the description covers the essential action and output content adequately. It is only slightly incomplete on usage routing and persistence/error behavior, which keeps it at 4 rather than 5.
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?
There is a single parameter and schema description coverage is 100%, with the schema already documenting the SKU format and an example value. The description only restates that the SKU identifies the product to generate copy for, adding no format or constraint detail beyond the schema. Baseline 3 applies.
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 states a concrete verb and resource: it looks up a product by SKU and generates marketing copy, then enumerates the artifacts produced (headline, short/long description, bullets, SEO tags). That is far more specific than the name alone and clearly sits apart from the inventory/order siblings. It stops short of explicitly naming an alternative tool, so it lands at 4 rather than 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?
Usage is only implied: an agent can infer you call this when you need marketing copy for a SKU. There is no statement of when to prefer it over siblings (e.g., versus list_all_products for raw product data) and no prerequisites such as the SKU needing to exist. That is the definition of a minimum-viable 3.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
find_ordersFind OrdersA
Looks up orders by exact order id or by customer name (case-insensitive substring match, so 'maya' finds 'Maya Chen') and returns each order's line items enriched with product name, unit price and line total. This is the drill-down behind the aggregates: analyze_sales_metrics reports what sold in total, this reports what a single order or customer actually bought. Results are newest first. Line prices come from the current catalog; a line whose product is no longer catalogued reports null rather than an invented price. Supplying both filters requires an order to satisfy both; the echoed 'filters' block reports the values actually matched on. A filter that matches nothing is a successful lookup with count 0 and an empty 'orders' array — the same answer list_all_products gives — not a tool error. Results are deliberately uncapped by default and there is no pagination: 'customer_name' is a substring match, so a broad query returns every matching order in the dataset (a one-letter name matches most of it). Pass 'limit' to bound a broad query — 'totalMatches' always reports how many matched in full, so a capped answer cannot be mistaken for a complete one. Narrow the filter rather than expecting a page, and prefer 'order_id' when you want a single order.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Return at most this many matches, newest first. 'totalMatches' still reports the full match count. Omit to return every match. | |
| order_id | No | Exact order id to fetch, e.g. 'ord_1042'. Case-insensitive. | |
| customer_name | No | Customer name to match, case-insensitively as a substring: 'maya' matches 'Maya Chen'. Use this to answer questions like 'what did Maya order?'. |
Output Schema
| Name | Required | Description |
|---|---|---|
| count | Yes | |
| limit | Yes | |
| orders | Yes | |
| filters | Yes | |
| totalMatches | Yes |
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 thoroughly: newest-first ordering, uncapped-by-default with no pagination, null prices for de-catalogued products rather than invented ones, a broad substring filter matching most of the dataset, the echoed 'filters' block, and that a zero-match result is a success not a tool error. These are exactly the failure modes an agent would otherwise stumble into.
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 core purpose and the aggregate-vs-drill-down framing are front-loaded, and each subsequent sentence adds a distinct behavioral fact. The passage is long and dense, and a couple of points (the list_all_products aside, the one-letter-name aside) could be trimmed, but there is little filler.
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?
An output schema exists so return values need not be spelled out, yet the description still clarifies the highest-risk aspects of the response (ordering, cap vs totalMatches, null prices, empty-array success). Combined with the behavioral coverage, an agent has everything needed to call it correctly and interpret the result.
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, but the description adds real meaning beyond the schema: the substring/case-insensitive behavior with a concrete example, the AND semantics when both filters are supplied, and the interplay of 'limit' with the always-full 'totalMatches' count. This goes beyond restating the field descriptions.
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 ('looks up orders') plus two distinct lookup modes (exact order_id or substring customer_name) and the enrichment applied to returns (product name, unit price, line total). It explicitly distinguishes itself from the sibling analyze_sales_metrics as 'the drill-down behind the aggregates', so an agent can route without opening another schema.
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?
Gives explicit when-to-use routing ('prefer order_id when you want a single order', narrow the filter rather than expecting a page), names the alternative (analyze_sales_metrics) and the condition that selects it. It also clarifies the empty-result and combined-filter cases, leaving nothing to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_low_stock_alertsGet Low Stock AlertsA
Scans inventory and returns InventoryAlert objects for every product at or below a stock threshold. Products under 3 units are flagged 'critical'; everything else at or under the threshold is flagged 'low'. Results are sorted by current stock ascending (most urgent first). An optional category restricts the scan to one category; the echoed 'filters' block reports the category actually applied.
| Name | Required | Description | Default |
|---|---|---|---|
| category | No | Restrict to a single category, e.g. 'tech', 'apparel', or 'home'. Case-insensitive. Omit to cover the whole catalog. | |
| threshold | No | Stock level at or below which a product triggers an alert. Defaults to 5 if omitted. |
Output Schema
| Name | Required | Description |
|---|---|---|
| alerts | Yes | |
| filters | Yes | |
| alertCount | Yes | |
| criticalCount | Yes | |
| thresholdUsed | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full behavioral burden and does well: it discloses the severity classification rule (under 3 units = critical, otherwise low), the sort order (stock ascending, most urgent first), and the echoed filters block. It does not mention permissions, rate limits, or pagination, which are the remaining gaps for an unannotated read 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?
Three dense sentences, each earning its place: trigger condition first, classification and ordering second, filtering/echo behavior last. No filler and no restatement of the title.
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 an output schema present, return values need not be explained, and the description covers the alert logic, sorting, and filtering fully. Only minor operational context (permissions, whether scanning is expensive) is absent, which is a small gap for a read-only tool.
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 100%, so both parameters (category with case-insensitivity and examples, threshold with default and exclusivity) are already fully documented in the schema. The description reinforces their effect — category restricts the scan, the applied category is echoed — but adds no new syntax or format detail, so baseline 3 applies.
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 (scans inventory, returns InventoryAlert objects) plus the precise triggering condition (at or below a stock threshold). It is clearly distinct from siblings like list_all_products and smart_restock_predictor, so an agent can route to it without opening the schema.
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 the tool applies (finding products at or below a threshold) and notes that omitting category covers the whole catalog, but it never names an alternative such as smart_restock_predictor or states when not to use this tool. Usage is inferable rather than explicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_all_productsList All ProductsA
Returns the product catalog, optionally filtered by category, a min/max price range, or a free-text search. Use this to browse inventory or to find a specific product by name, SKU, description or tag before recommending, restocking, or drafting copy for products.
| Name | Required | Description | Default |
|---|---|---|---|
| search | No | Free-text search matched against product name, SKU, description, tags and category. Case-insensitive substring, so 'merino' finds the Highland Merino Wool Sweater. Results are ranked by match quality, so a product whose own name or tag is the query comes first; the set of matches is the same either way. Combine with the other filters to narrow further. | |
| category | No | Restrict results to a single category, e.g. 'tech', 'apparel', or 'home'. Case-insensitive. Omit to include all categories. | |
| max_price | No | Only include products priced at or below this amount, in USD. | |
| min_price | No | Only include products priced at or above this amount, in USD. |
Output Schema
| Name | Required | Description |
|---|---|---|
| count | Yes | |
| filters | Yes | |
| products | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are supplied, so the description carries the full behavioral burden. It conveys that filters are optional and that the unfiltered default returns the whole catalog, which is useful, but says nothing about result size, pagination, ordering guarantees beyond what the schema already states, or permissions. Adequate but thin for a no-annotation 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 sentences, front-loaded with the return behavior and then the use cases; no filler or repetition. The second sentence is somewhat long with a four-item enumeration, but each item (recommending, restocking, drafting copy) maps to real sibling workflows and earns its place.
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 a 100%-covered schema and an output schema present, the description need not restate parameters or return shape, and it correctly delegates those. What remains missing is only the low-risk behavioral profile (read-only, no side effects, result volume) for a tool with no annotations, which is a minor gap given the obvious read semantics of '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?
Schema description coverage is 100% and the search parameter's ranking/substring semantics are fully documented in the schema, so the baseline is 3. The description only summarizes the filter categories ('category, a min/max price range, or a free-text search') without adding syntax, defaults, or combination behavior beyond what the schema already provides.
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 ('Returns the product catalog') and enumerates the available filters, so the agent knows exactly what this tool produces. It does not name or contrast with any sibling (e.g. find_orders, get_low_stock_alerts), so differentiation is inferred from the resource noun rather than stated.
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?
Gives clear usage context: browse inventory or locate a product by name/SKU/description/tag, and lists downstream scenarios (recommending, restocking, drafting copy) that motivate the call. No explicit when-not-to-use or alternative-tool routing is provided, so it stops short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
reset_demo_stateReset Demo StateA
Write-action tool: discards every simulated order and inventory change made during this or any earlier session, restoring the original seed catalog. Use it to undo exploratory ordering before reporting results, so the numbers you hand back reflect the real dataset rather than your own test orders.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| reset | Yes | |
| orders | Yes | |
| products | Yes |
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 real work: it explicitly labels this a write-action tool and discloses the exceptionally wide destructive scope (all simulated changes from this or any earlier session). It stops short of stating irreversibility/confirmation requirements, but the safety profile is otherwise well covered.
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-loads the 'Write-action tool' warning, then the effect, then the rationale. The final clause about reporting real numbers is slightly redundant with 'before reporting results,' but it reinforces intent rather than padding.
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?
Output schema exists so return values need no explanation, and there are no parameters or annotations to compensate for. Scope, intent, and destructive warning are all present for a zero-arg tool.
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 baseline there is no parameter semantics to explain and no gap in the description. No misleading parameter claims are made.
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?
Names a specific action (discards/restores) on a specific resource (simulated orders and inventory changes, seed catalog). An agent can immediately distinguish this reset tool from simulate_order_placement or find_orders in the sibling set.
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?
Gives a clear when-to-use context: undo exploratory ordering before reporting results. It does not name an explicit alternative tool or a when-not-to-use condition, but the trigger condition is unambiguous.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
simulate_order_placementSimulate Order PlacementA
Write-action tool: places a new simulated order, validating stock availability for every line item, decrementing inventory counts, computing the order total from current catalog prices, and returning a success receipt with the updated stock levels. Rejects the entire order (no partial writes) if any item is unavailable or under-stocked. The whole read-validate-write runs inside the provider's transaction, so a concurrent order cannot both pass a stock check and oversell. This permanently changes the dataset until reset_demo_state is called.
| Name | Required | Description | Default |
|---|---|---|---|
| items | Yes | One or more line items for this order. | |
| customer_name | Yes | Full name of the customer placing the order. |
Output Schema
| Name | Required | Description |
|---|---|---|
| receipt | Yes | |
| success | Yes | |
| updatedStockLevels | Yes |
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 thoroughly: all-or-nothing writes ('no partial writes'), transactional isolation against concurrent oversell, and permanent dataset mutation until reset_demo_state is called. These are exactly the mutation semantics an agent must know before invoking.
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?
Three dense sentences, front-loaded with the write-action framing, with zero filler. Each sentence adds a distinct fact: what it does, atomicity, and transaction/persistence behavior.
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?
An output schema exists, so the description needn't detail return values, yet it still previews the 'success receipt with updated stock levels'. Combined with the atomicity and persistence notes, an agent has everything needed to call this safely.
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 100%, so customer_name, items, product_id, and quantity are already documented in the schema. The description adds behavioral meaning (per-line-item stock validation, totals from current catalog prices) but no syntax or constraint detail beyond the schema, matching the baseline 3.
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?
Opens with an explicit verb+resource ('places a new simulated order') and enumerates the concrete operations performed (stock validation, inventory decrement, total computation). It also distinguishes itself from siblings by naming reset_demo_state as the inverse operation.
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?
Frames the tool as a 'Write-action tool' and states the persistence consequence plus the reset_demo_state escape hatch, which tells an agent when this is appropriate versus read-only siblings. It stops short of explicitly contrasting against alternatives like find_orders or list_all_products, so a 4 rather than 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
smart_restock_predictorSmart Restock PredictorA
Evaluates every low-stock item and recommends an exact reorder quantity. The recommendation is derived from each product's demand velocity (units sold per day over recent order history), projected demand across an assumed 14-day supplier lead time plus a 7-day safety buffer, minus current stock on hand. Items with no recent sales history fall back to a conservative flat restock quantity. Results are ordered by days of cover (stock remaining / daily velocity), so the first recommendation is the item that runs out first; items with no measurable demand report a null daysOfCover and sort last. An optional category restricts the plan to one category; the echoed 'filters' block reports the category actually applied.
| Name | Required | Description | Default |
|---|---|---|---|
| category | No | Restrict to a single category, e.g. 'tech', 'apparel', or 'home'. Case-insensitive. Omit to cover the whole catalog. | |
| threshold | No | Stock level at or below which a product is considered for restocking. Defaults to 5 if omitted. |
Output Schema
| Name | Required | Description |
|---|---|---|
| window | Yes | |
| filters | Yes | |
| assumptions | Yes | |
| thresholdUsed | Yes | |
| recommendations | Yes |
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 it well: it discloses the demand-velocity formula, the hardcoded 14-day lead time and 7-day safety buffer assumptions, the flat-quantity fallback for items with no history, and the days-of-cover sort with nulls last. It never explicitly states this is a non-mutating computation, which is the only real gap.
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 core purpose is front-loaded in the first sentence and the remaining detail is dense rather than padded. Slightly long, but each sentence (formula, assumptions, fallback, sort order, filter echo) carries information the agent needs to trust the output.
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?
An output schema exists, so return values need not be explained, and the description still covers ordering semantics, null daysOfCover behavior, and filter echoing. For a two-parameter computed-read tool this is complete.
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 100%, so the schema already documents both category and threshold (including the default of 5). The description adds the useful detail that the applied category is echoed back in a 'filters' block, but contributes nothing for threshold — baseline 3 applies.
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 ('Evaluates every low-stock item and recommends an exact reorder quantity'), which distinguishes it from the alert-listing sibling get_low_stock_alerts — this tool quantifies, that one notifies. An agent can tell what it produces without opening the schema.
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: you use it when you need reorder quantities for low-stock items, and the optional category narrows the plan. There is no explicit when-not guidance or reference to the sibling alert/product tools, so the agent must infer routing.
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.
1 tool update
v3.2.0- Changed
list_all_products1 field changed- changed
Input schema / properties / search / descriptionPrevious value: -"Free-text search matched against product name, SKU, description, tags and category. Case-insensitive substring, so 'merino' finds the Highland Merino Wool Sweater. Combine with the other filters to narrow further."New value: +"Free-text search matched against product name, SKU, description, tags and category. Case-insensitive substring, so 'merino' finds the Highland Merino Wool Sweater. Results are ranked by match quality, so a product whose own name or tag is the query comes first; the set of matches is the same either way. Combine with the other filters to narrow further."
8 tool updates
v3.0.1- First observed
analyze_sales_metrics - First observed
draft_product_copy - First observed
find_orders - First observed
get_low_stock_alerts - First observed
list_all_products - First observed
reset_demo_state - First observed
simulate_order_placement - First observed
smart_restock_predictor
TDQS
Scored across 8 tools
Each tool has a clearly distinct purpose: aggregate analytics (analyze_sales_metrics) vs. per-order drill-down (find_orders), inventory alerting (get_low_stock_alerts) vs. restock recommendation (smart_restock_predictor), plus catalog browse, copy generation, order simulation, and demo reset. The descriptions explicitly cross-reference each other to delineate boundaries, leaving little room for misselection.
Most names follow a verb_noun pattern (analyze_sales_metrics, list_all_products, find_orders, reset_demo_state, simulate_order_placement, draft_product_copy). Two deviate mildly: 'get_low_stock_alerts' inserts an adjective and 'smart_restock_predictor' uses an adjective_noun form with no verb. Still readable and largely predictable.
Eight tools is well within the sweet spot and each earns its place across the read/write lifecycle. No redundant or filler tools; the set is tightly scoped to a simulated commerce domain.
The surface covers catalog browse, order placement/lookup, analytics, inventory alerts, restock planning, copy generation, and state reset—core workflows are all present. Minor gaps exist around product CRUD (no create/update/delete of catalog items) and order mutation, though the demo/simulated framing makes these reasonable omissions.
Maintenance
Related MCP Connectors
Hosted MCP for e-commerce: live product catalog, stock, and pricing for AI agents.
A Model Context Protocol server for Wix AI tools
A comprehensive Model Context Protocol (MCP) server that enables AI assistants to interact with yo…
The Mercado Pago MCP Server implements the Model Context Protocol to provide AI agents and LLMs with access to Mercado Pago's APIs and tools within compatible development environments. It acts as an intermediary that translates Mercado Pago resources into executable functions (tools) that AI applications can invoke to perform actions and automate flows. The server simplifies integration, enables using documentation to implement or improve code, and optimizes operations through natural language interactions without manual implementations.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceA Model Context Protocol server that provides real-time access to MongoDB product data, enabling sophisticated e-commerce queries with price range filters, category searching, and product recommendations through a conversational interface.-
- FlicenseNot gradedqualityDmaintenanceA Model Context Protocol server that enables AI assistants to interact with Saleor e-commerce data including products, orders, customers, and more.3-
- AlicenseNot gradedqualityBmaintenanceA Model Context Protocol server that connects AI agents to the Shopify Admin GraphQL API, enabling management of products, orders, customers, and more through natural language.1,777 npm6MIT
- AlicenseAqualityFmaintenanceAn MCP server that gives AI agents eyes on any e-commerce storefront, enabling scraping, analysis, and comparison through the Model Context Protocol.1446 npmMIT