Inspiration

Smart pet devices are returned at a punishing rate, and mostly not because they are broken. They come back because of a mismatch that was knowable before checkout and invisible while scrolling:

  • a 2.4GHz-only device meeting a 5GHz-only mesh router — it will never finish setup
  • a 4G tracker on LTE bands that do not exist in the buyer's country
  • a companion app not published in the buyer's region
  • a single-cat litter box arriving in a two-cat home

Every one of those sits somewhere on the product page. Nobody reads it. So we built the store that reads it for you and then says no.

What it does

MintPaw is a live Shopify storefront selling five smart pet devices. Its WebMCP layer is not a faster way to buy — it is a gate.

An agent records the shopper's household: species, weight, how many animals share the device, which Wi-Fi bands the router actually broadcasts, country, and willingness to add a cellular plan. It then returns, per product, a verdict of ok / caution / unknown / blocked with the specific reason in plain language.

A blocked product cannot be added to the cart. The tool refuses, the Add to cart button goes dead and relabels itself "Not compatible with your home", and Shopify's express checkout button is removed from the page.

A caution product is also held back until the agent has actually told the shopper the caveat and passed acknowledged_caveats: true. Informed consent, enforced in code rather than requested in a prompt.

And the store says what it does not know. Our product data comes from Alibaba sourcing documents full of unconfirmed manufacturer claims. Instead of laundering those into spec, every tool returns them separately as notYetVerifiedByMintPaw"the listing says 10000mAh, MintPaw has not measured it." unknown and ok are deliberately different verdicts.

How we built it — and the discovery that shaped the whole project

Partway in we found that Shopify's storefront now injects its own WebMCP adapter automatically (cdn.shopify.com/storefront/webmcp/webmcp-0.1.1.js). Out of the box our store already exposed ten generic commerce tools: search_catalog, get_product, get_cart, update_cart, cancel_cart, proceed_to_checkout, browse_store, show_variant, manage_orders and search_shop_policies_and_faqs.

Our first draft had re-implemented five of those and collided with get_product outright — two tools with one name and an agent picking between them at random. We deleted it.

That reframed the project:

The interesting question WebMCP raises for a merchant is not "how do I expose my storefront?" — the platform now does that. It is "what do I know that the platform cannot?"

For MintPaw that is compatibility: which device works in this home for this animal, and which claims we have not verified. That knowledge exists nowhere in Shopify's data model.

So our seven tools are the layer above the platform, with zero name overlap:

Tool
set_household_profile always on pet, weight, count, Wi-Fi bands, country, SIM willingness
get_household_profile always on read it back — the shopper may have edited it by hand
clear_household_profile always on erase it, and withdraw the gated tools
check_compatibility always on the core: per-product verdict and reason
explain_product_fit always on one product in depth + every unverified claim
find_compatible_alternative gated what works instead; "nothing does" is a valid answer
add_compatible_to_cart gated refuses blocked items; holds caveats until acknowledged

The two gated tools do not exist until a household profile does — without one they cannot answer honestly, so they are withdrawn rather than left to guess. On the live page the tool count goes 15 → 17 the moment a profile is set, and back to 15 when it is cleared. Registration uses AbortController, per the spec.

Why cross-border sourcing makes this necessary

Every product here is sourced on Alibaba.com and shipped to a buyer in another country. That is not incidental — it is the reason the gate has to exist. Cross-border sourcing produces a class of failure a domestic store never sees, and our own sourcing research (done with Alibaba Accio Work) turned up exactly these:

Sourced fact What it means for the buyer
The feeder lists plug variants for 8 countries, input voltage not stated A plug adapter changes the pins, not the voltage. A 220–240V unit on 120V US mains is destroyed on first use.
The tracker lists LTE 850/900/1800/1900 MHz — frequencies, no band numbers, no 700MHz US carriers lean on 700MHz for rural and in-building coverage. Bars on the street, nothing in the basement.
Tuya companion app, regions not stated The app is published per app-store region. No app, no setup.
"Waterproof" with no IP rating A word, not a specification.

Both of the first two are live checks in check_compatibility, driven by the shopper's country.

Provenance, not just "unverified"

Every field carries where its value came from, and the verdict engine reads it: confirmed (supplier's written spec), platform_listed (on the Alibaba detail page), inferred_tbc (a conservative inference — a hint, not a fact), pending (no source; the supplier must be asked).

Not one field in this catalogue is confirmed. No supplier has returned written specifications, and the store says so on the page, next to the price. The open questions we have put to each supplier and not had answered are published there too.

An earlier version of this data asserted four products were 2.4GHz-only and that the litter box had a multi-cat limit. Re-checking the listings showed both were our guesses. We deleted them. That made the demo less dramatic and the store more honest — and we rewrote the tests to assert the honest behaviour instead.

People and agents on the same object

The product template already shipped an "AI Compatibility Check" block with five rows, rendered as static placeholders. Rather than bolt on a competing widget, we restructured the verdict engine around exactly those five axes — Network compatibility, Region lock, Power requirement, Pet profile match, Essential extras — so the agent fills in the storefront's own block.

The shopper is not reading a chat transcript about the product. They are watching the product page itself change, row by row, with a panel in the corner logging every tool call and letting them clear the profile by hand. WebMCP's trust model assumes a human is watching; this is the watching part.

One source of truth for the shopper and the agent

Every product arrived with no description at all. The supplier gave us specification fragments, not marketing copy — and writing confident prose around numbers we have not verified is the exact thing this store exists to avoid.

So the product copy is rendered from MINTPAW_COMPAT — the same record, the same fields, in the same order that check_compatibility reads. A shopper and an agent cannot be told different things about a product, because there is only one source for both.

It also means the unverified claims appear on the page, under a heading that reads "What we haven't checked ourselves", rather than only inside a tool response the shopper will never see. The honesty is not a property of the agent. It is a property of the store.

Challenges we ran into

  • Not duplicating the platform. Described above. It cost a rewrite, and it was the best thing that happened to the project.
  • A stale-verdict bug. Changing the household left the previous run's verdicts painted on the page. Our own test suite caught it, not a person.
  • Dawn renders two forms pointing at /cart/add, and only one holds the submit button; the obvious selector picks the wrong one.
  • The refusal was cosmetic at first. We disabled Add to cart, but Shopify's express checkout button sat right underneath, still live, one tap from payment. A gate with a hole in it is not a gate.

Accomplishments we're proud of

It is a real store, live, with a refusal you can trigger yourself in about thirty seconds. And it ships 29 headless tests that run the real theme asset against the real catalogue and assert the things that would make the store a lie if they broke — chiefly that a 2.4GHz device is never ok in a 5GHz-only home, and that a hard block cannot be acknowledged away.

What we learned

WebMCP changes what a merchant is for. When the platform hands every store the same generic commerce tools, exposing your catalogue stops being a differentiator. What is left is the judgement you can encode that nobody else has — and, unexpectedly, the willingness to encode a no.

What's next for MintPaw

Compatibility data currently ships as a reviewable static asset; the Shopify metafield schema is written and the Liquid path is in the repo behind one flag. Beyond that: real verification work to retire the unverified_claims list one entry at a time, which is the only way an unknown verdict ever becomes an ok.

One limitation we'd rather state than hide

Shopify's built-in update_cart will happily add a product we blocked, and a merchant cannot unregister a platform-provided tool. We describe ours as the one that knows about this shopper's router, and we make any bypass visible in the panel — but a real fix needs a way for a page to constrain tools it did not register. That feels like a genuine gap in the spec, and it is worth raising.

Built With

Share this project:

Updates

Submission history