Repository navigation
Products from JSON LD
Most WebMCP guidance asks you to write tools. This page is about the case where you have already written them and do not know it.
If your site sells things, it almost certainly carries schema.org Product
markup — the JSON-LD block search engines read to understand your catalogue. It
is structured, it is typed, it uses a published vocabulary, and somebody is
already keeping it current because search rewards that. It is, in other words, a
product API that has been sitting in your <head> for years with no consumer.
<machvive-webmcp-products></machvive-webmcp-products>That is the integration. One tag, no backend, no new data, nothing to keep in sync.
| Tool | |
|---|---|
search_products |
Free text plus category, brand, availability, minPrice, maxPrice, limit, offset
|
get_product |
One product in full by SKU, MPN or GTIN, including its original JSON-LD |
list_product_facets |
The categories, brands, stock states and price range present on the page |
All three are read-only. They search and read; they never add to a cart, place an order or submit anything. That is a deliberate boundary, and it is what makes the component safe to publish automatically and why it holds no credentials. If you want an agent to do something, that is a tool you write — see Magnet Integration for a human-in-the-loop example.
This is the part worth understanding, because it is what separates a usable tool from one an agent fumbles.
category, brand and availability are declared in the schema as enums
built from the products actually on the page. An agent asking for
category: "Actuators" when your data says "HVAC Actuators" gets nothing and
has no way to find out why. With an enum, it can read the valid values straight
off the schema — or call list_product_facets and get them explicitly.
The same property gives you a working UI for free: the
inspector renders an enum as a
<select>, so your filters become dropdowns of real values with no
configuration at all. Change the catalogue, call load(), and the dropdowns
follow.
Real JSON-LD is correct-but-inconsistent, and a reader that handles only the tidy shape works on a fixture and fails on the web. The normalizer therefore walks the document recursively rather than looking for known containers, and copes with:
-
@graph,ItemList/itemListElement/ListItem, a bare array, a loneProduct, or aProductnested somewhere nobody anticipated -
@typeas a string, an array, or a full URL -
brand,categoryandselleras a plain string or a node -
imageas a URL, an array, or anImageObject -
offersas an object or an array — where the first entry is often a stub carrying only a url, and taking it blindly reports the product as unpriced -
AggregateOffer, reported at its low price, because "from $198" is actionable and a midpoint nobody can pay is not - every
gtinflavour collapsed into one field - prices as decorated strings (
"$1,299.00") -
availabilityanditemConditionarriving ashttps://schema.org/InStockrather than a word, which must be reduced or the filter is unusable - a malformed block, which is skipped rather than taking the page's other blocks down with it — pages carry generated blocks beside a hand-written one, and the hand-written one has the trailing comma
The same product appearing in both an ItemList and a BreadcrumbList is
deduplicated, keeping whichever copy is richer.
| Attribute | |
|---|---|
src |
Optional JSON-LD URL. Omit to read the page's own markup |
no-tool |
Read the data but publish nothing |
theme |
light or dark
|
const el = document.querySelector('machvive-webmcp-products');
el.products; // the normalized catalogue
el.facets; // categories, brands, availability, price range
await el.load(); // re-read and republish after the page's JSON-LD changesOne tool set per page however many elements you place; the first owns it and hands over if it is removed. All three tools share one registration signal, so removing the owning element withdraws them together.
It is exported independently, because it is useful without the element — in a build step, a fixture, or simply to see what an agent would make of a page:
import {
collectProducts, normalizeProduct, facetsOf, readDocumentJsonLd
} from '@machfivetechchicago/machvive-webmcp-ai/webmcp-products';
const products = collectProducts(readDocumentJsonLd(document));
console.log(facetsOf(products));A tool result lands in an agent's context window. A catalogue of three thousand products returned in one call is not a helpful answer; it is an expensive way to fail.
So search_products returns a compact summary — name, sku, brand, category,
price, currency, availability, url — capped at 50 with a default of 10, and an
explicit truncated flag. The flag matters: an agent that cannot distinguish a
page from a complete answer will confidently report "there are 10 products".
Page through with offset, and use get_product when the full record and the
original JSON-LD are actually wanted.
- Machvive WebMCP Polyfill Web Component Lib — the full component guide
- WebMCP as a Business Accelerator — why an agent is not just another visitor
- WebMCP Canonical Use Cases — the two ways an agent reaches your page