Agent commerce with mock.shop
mock.shop supports Universal Commerce Protocol (UCP)
version 2026-08-25 for catalog search and mock carts. Each store has its
own catalog and carts, selected by the request hostname. The apex mock.shop
serves the default demo store.
Discover a store
Read https://mock.shop/llms.txt to choose a store. For example:
curl https://pets.mock.shop/.well-known/ucp
curl https://pets.mock.shop/api/ucp/mcp \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'
The discovery document advertises dev.ucp.shopping.catalog.search and
dev.ucp.shopping.cart, plus the MCP endpoint on that same host. The endpoint
is anonymous, accepts one JSON-RPC request per POST, and uses the MCP SDK's
standard initialize, ping, tools/list, and tools/call methods. It does
not need a session ID or a persistent event stream.
Publish your agent profile
UCP tool calls require a profile describing your agent's supported protocol
version and capabilities. Host this JSON on a public HTTPS URL, such as
https://your-agent.example/ucp-profile.json, with
Content-Type: application/json and Cache-Control: public, max-age=60:
{
"ucp": {
"version": "2026-08-25",
"services": {},
"capabilities": {
"dev.ucp.shopping.catalog.search": [{
"version": "2026-08-25",
"spec": "https://ucp.dev/2026-08-25/specification/shopping/catalog/search",
"schema": "https://ucp.dev/2026-08-25/schemas/shopping/catalog_search.json"
}],
"dev.ucp.shopping.cart": [{
"version": "2026-08-25",
"spec": "https://ucp.dev/2026-08-25/specification/shopping/cart",
"schema": "https://ucp.dev/2026-08-25/schemas/shopping/cart.json"
}]
},
"payment_handlers": {}
},
"keys": []
}
initialize and tools/list can run without a profile. Every tools/call
request includes its URL at params.arguments.meta["ucp-agent"].profile.
Only capabilities present in both the store's and your agent's profile can
run. Profiles are cached for one minute, must use HTTPS on port 443, and
cannot redirect or resolve to private addresses.
You can run mock.shop locally and call its MCP endpoint using the configured development shop host. The public-address restriction applies to the agent profile that mock.shop fetches, not to the incoming MCP request. Use a public HTTPS profile for local integration testing; profiles hosted on localhost or private networks are rejected. Unit tests use a stubbed profile fetch.
Search the catalog
Send this JSON body to the store's /api/ucp/mcp endpoint, replacing the
profile URL with your own:
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "search_catalog",
"arguments": {
"meta": {"ucp-agent": {"profile": "https://your-agent.example/ucp-profile.json"}},
"catalog": {"query": "dog", "pagination": {"limit": 10}}
}
}
}
Results appear in result.structuredContent, with a JSON text copy in
result.content for MCP clients that use text. Product variants have IDs
that can be used as cart item IDs. Search uses mock.shop's existing text
matching; an empty catalog object browses the store.
Supported filters are catalog.filters.categories (Shopify taxonomy IDs
returned in product categories) and catalog.filters.price.min / max.
Prices and cart totals are integers in ISO 4217 minor units: USD 18.00
is 1800; JPY 1800 is 1800. The store's currency is fixed. If supplied,
context.currency must match it. Other context hints do not change mock prices
or localization. Search and cart requests accept optional attribution and
signals objects; carts also accept buyer. They are validated but are not
saved to the cart or used for personalization, tracking, or checkout. These
objects are filtered from request parameter logs.
Search returns up to 25 products per page and up to 100 variants per product.
Use the returned pagination.cursor with the same query and filters for the
next page. JSON key order, empty options, and nonbinding context hints do not
affect pagination. Cursors expire after one hour. The Storefront GraphQL API remains
available for larger variant lists and other catalog operations.
Build and manage a cart
Copy a variant's id from search into item.id:
{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "create_cart",
"arguments": {
"meta": {
"ucp-agent": {"profile": "https://your-agent.example/ucp-profile.json"},
"idempotency-key": "550e8400-e29b-41d4-a716-446655440000"
},
"cart": {
"line_items": [{"item": {"id": "VARIANT_ID_FROM_SEARCH"}, "quantity": 2}]
}
}
}
}
| Tool | Arguments besides meta |
Behavior |
|---|---|---|
create_cart |
cart.line_items |
Creates a mock cart. |
get_cart |
id |
Reads the cart and estimated totals. |
update_cart |
id, cart.line_items |
Replaces the entire item list. An empty list clears it. |
cancel_cart |
id |
Removes the cart. Further reads return not_found. |
Cart writes require a random meta["idempotency-key"] with at least 128 bits
of entropy, such as UUIDv4 (22–255 characters). Retry with the identical JSON
request bytes, including the JSON-RPC id, metadata, whitespace, and key
order. Use a new key whenever the body changes. A reused key with a different
body returns JSON-RPC error -32000 with data.code: idempotency_conflict.
Successful write responses are retained for 24 hours, scoped to the store,
agent profile URL, and operation. Storage failures return HTTP 503 without
committing cart changes; retry the identical request.
Profile discovery or version failures return JSON-RPC error -32001. An
incompatible capability returns a UCP tool result with isError: true and
capabilities_incompatible. Optional metadata and nonbinding context hints
are accepted; only context.currency affects validation. Other context
fields do not change mock prices, language, availability, or checkout.
Carts use the existing mock.shop storage, IDs, 10-day renewable expiry, validation, and limits. Up to 250 lines can be supplied in one request. Updates are atomic: invalid items leave the previous cart intact. A cart or variant from another store cannot be used here. The same cart IDs work with the store's Storefront GraphQL API.
Quantities count whole items. An optional item.quantity_unit can explicitly
assert unit: "C62", with scale omitted or set to 0, and a display_text
string. Its display text and optional increment do not change mock quantities.
Other sale units are rejected with a recoverable invalid_input result.
Line id and parent_id strings are accepted on updates, but the mock rebuilds
flat cart lines and does not retain those identifiers or nested relationships.
Existing mock checkout
Checkout stays mocked: no payment is taken, nothing ships, and no real order is placed. The existing storefront checkout uses the browser's cart cookie; these UCP tools do not set that cookie or transfer an API cart into the browser. Use the storefront normally to walk through its mock checkout.
There are no UCP create_checkout, update_checkout, complete_checkout,
payment, fulfillment, or order tools. The discovery profile does not
advertise those capabilities or payment handlers.