UCP Checker

How an agent finds a product

A UCP agent doesn't read your product pages. It asks your catalogue, and gets back the products as data: what each one is, what it costs, what can be bought and whether it's in stock. Here is what that looks like, call by call, on a real store.

Two ways to read a store

Reading the page
<h1 class="pdp-title">Red Roses</h1>
<span class="price">$35</span>
<s class="was">$42</s>
<select id="size">…</select>
<button>Add to bag</button>
  • Which number is the price, and in which currency?
  • Which size is in stock?
  • Will the layout be the same tomorrow?
Asking the catalogue
"price": { "amount": 3500, "currency": "USD" },
"variants": [{
  "id": "bouquet_roses",
  "availability": { "status": "in_stock" }
}]
  • The price is a number, in a named currency.
  • Each variant says whether it can be bought.
  • The shape is set by the release, not the theme.

One product, as an agent receives it

The first result search_catalog returned for "roses" on Northlight Flowers, our test store, split into the parts an agent uses.

  1. {
      "id": "bouquet_roses",
      "title": "Bouquet of Red Roses",
      "url": "https://flowers.ucpsandbox.com/products/bouquet_roses",
    1id, title, url

    What it is

    A stable id the agent can look up again or put in a cart, the name it shows the buyer, and the page to send them to.

    Every product has an id and a title; an id that changes between calls breaks the cart.

  2.   "description": {
        "plain": "A classic dozen of long-stem red roses."
      },
    2description

    What the buyer is told

    Plain text the agent can quote or summarise. The store can also send markdown or HTML, and the agent has to strip it.

    Plain text always, and an HTML version too if the description has formatting. On our test store this was the one rule to consider: no product sends an HTML version.

  3.   "price_range": {
        "min": {
          "amount": 3500,
          "currency": "USD"
        },
        "max": {
          "amount": 3500,
          "currency": "USD"
        }
      },
    3price_range

    What it costs

    The lowest and highest variant price, so the agent can compare without opening every variant.

    Amounts are whole numbers in minor units with an ISO currency: 3500 USD is $35.00, not $3,500.

  4.   "variants": [
        {
          "id": "bouquet_roses",
          "price": {
            "amount": 3500,
            "currency": "USD"
          },
          "availability": {
            "available": true,
            "status": "in_stock"
          }
        }
      ],
    4variants[]

    What can be bought

    Each size or colour as its own id, price and stock, with the ways it can reach the buyer (here shipping or pickup). The variant id, not the product id, is what usually goes in the cart.

    Every variant has an id, a price and an availability.

  5.   "media": [
        {
          "type": "image",
          "url": "https://flowers.ucpsandbox.com/images/flowers/bouquet_roses.webp",
          "alt_text": "Bouquet of Red Roses"
        }
      ]
    }
    5media[]

    What it looks like

    Images the agent can show beside its answer, with alt text it can read out.

    Image URLs are https and load; alt text describes the product.

The Catalog Validator checks every product a search returns against 33 rules like these. Run it on your store.

From a search to an order

Discovery is the first three calls: read the profile, list the tools, search. The other four are what discovery is for. Choose a call to see what was sent and what came back.

Recorded on 16 October 2026 against Northlight Flowers, our test store at flowers.ucpsandbox.com (release 2026-08-25, test cards, nothing is for sale). Responses are trimmed to the fields that matter, nothing added; long ids are cut short with …, and the agent's own profile is shown as agent.example.

1

Read the profile

The agent asks the store's fixed address what it offers, before it sends anything else.

GET /.well-known/ucp HTTP/1.1
Host: flowers.ucpsandbox.com
Accept: application/json
200, JSON: release, services, capabilities

{
  "ucp": {
    "version": "2026-08-25",
    "services": {
      "dev.ucp.shopping": [
        {
          "transport": "rest",
          "endpoint": "https://flowers.ucpsandbox.com/ucp"
        },
        {
          "transport": "mcp",
          "endpoint": "https://flowers.ucpsandbox.com/mcp"
        }
      ]
    },
    "capabilities": {
      "dev.ucp.shopping.catalog.search": "…",
      "dev.ucp.shopping.catalog.lookup": "…",
      "dev.ucp.shopping.cart": "…",
      "dev.ucp.shopping.checkout": "…",
      "dev.ucp.shopping.fulfillment": "…",
      "dev.ucp.shopping.order": "…"
    },
    "payment_handlers": {
      "dev.mock.payment_handler": "…"
    }
  }
}

What the agent knows now. Release 2026-08-25, an MCP endpoint, catalogue search and checkout declared, one payment handler. Enough to go on.

2

List the tools

An MCP client asks the endpoint from the profile which tools it serves. Their names are fixed by the UCP binding.

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/list",
  "params": {}
}
15 tools

{
  "tools": [
    "search_catalog",
    "lookup_catalog",
    "get_product",
    "create_cart",
    "get_cart",
    "update_cart",
    "cancel_cart",
    "create_checkout",
    "get_checkout",
    "update_checkout",
    "complete_checkout",
    "cancel_checkout",
    "get_order",
    "search_locations",
    "lookup_locations"
  ]
}

What the agent knows now. 15 tools, each with an inputSchema. The ones it needs for this run are all there.

4

Put it in a cart

dev.ucp.shopping.cart

A line item is an id from the catalogue and a quantity. The store prices it and returns the cart.

{
  "meta": {
    "ucp-agent": {
      "profile": "https://agent.example/.well-known/ucp"
    }
  },
  "cart": {
    "line_items": [
      {
        "item": {
          "id": "bouquet_roses"
        },
        "quantity": 1
      }
    ]
  }
}
a cart, total 3500 USD

{
  "id": "01a14534-5383-…",
  "currency": "USD",
  "line_items": [
    {
      "id": "li_3",
      "item": {
        "id": "bouquet_roses",
        "title": "Bouquet of Red Roses",
        "price": 3500
      },
      "quantity": 1
    }
  ],
  "totals": [
    {
      "type": "subtotal",
      "amount": 3500
    },
    {
      "type": "total",
      "amount": 3500
    }
  ],
  "continue_url": "https://flowers.ucpsandbox.com/cart",
  "expires_at": "2026-10-17T14:53:39+00:00"
}

What the agent knows now. A real cart that lasts a day, and a continue_url to hand the buyer to if the agent stops here.

5

Open a checkout

dev.ucp.shopping.checkout

The same line items, the buyer and a delivery address. The store says what is still missing in messages[].

{
  "meta": {
    "ucp-agent": {
      "profile": "https://agent.example/.well-known/ucp"
    }
  },
  "checkout": {
    "line_items": [
      {
        "item": {
          "id": "bouquet_roses"
        },
        "quantity": 1
      }
    ],
    "buyer": {
      "first_name": "Sam",
      "last_name": "Lee",
      "email": "[email protected]"
    },
    "fulfillment": {
      "methods": [
        {
          "type": "shipping",
          "destinations": [
            {
              "id": "dest_1",
              "first_name": "Sam",
              "last_name": "Lee",
              "street_address": "1 Main St",
              "address_locality": "Chicago",
              "address_region": "IL",
              "postal_code": "60601",
              "address_country": "US"
            }
          ],
          "selected_destination_id": "dest_1"
        }
      ]
    }
  }
}
status incomplete: choose a delivery option

{
  "id": "01a14534-5475-…",
  "status": "incomplete",
  "fulfillment": {
    "methods": [
      {
        "id": "method_1",
        "type": "shipping",
        "groups": [
          {
            "id": "group_1",
            "options": [
              {
                "id": "free-ship",
                "title": "Free Shipping",
                "totals": [
                  {
                    "type": "total",
                    "amount": 0
                  }
                ]
              },
              {
                "id": "std-ship",
                "title": "Standard Shipping",
                "totals": [
                  {
                    "type": "total",
                    "amount": 500
                  }
                ]
              },
              {
                "id": "exp-ship-us",
                "title": "Express Shipping (US)",
                "totals": [
                  {
                    "type": "total",
                    "amount": 1500
                  }
                ]
              }
            ],
            "selected_option_id": null
          }
        ]
      }
    ]
  },
  "messages": [
    {
      "type": "error",
      "code": "missing",
      "path": "$.fulfillment.methods[0].groups[0].selected_option_id",
      "content": "Choose a delivery option.",
      "severity": "recoverable"
    }
  ]
}

What the agent knows now. Status incomplete, and the store says exactly why: no delivery option yet. Three to choose from.

6

Choose delivery

dev.ucp.shopping.fulfillment

An update replaces the checkout, so the agent sends all of it again with the option chosen. Sending only the change was refused: "line_items is required on update."

{
  "meta": {
    "ucp-agent": {
      "profile": "https://agent.example/.well-known/ucp"
    }
  },
  "id": "01a14534-5475-…",
  "checkout": {
    "line_items": [
      {
        "item": {
          "id": "bouquet_roses"
        },
        "quantity": 1
      }
    ],
    "buyer": {
      "first_name": "Sam",
      "last_name": "Lee",
      "email": "[email protected]"
    },
    "fulfillment": {
      "methods": [
        {
          "id": "method_1",
          "type": "shipping",
          "destinations": [
            {
              "id": "dest_1",
              "first_name": "Sam",
              "last_name": "Lee",
              "street_address": "1 Main St",
              "address_locality": "Chicago",
              "address_region": "IL",
              "postal_code": "60601",
              "address_country": "US"
            }
          ],
          "selected_destination_id": "dest_1",
          "groups": [
            {
              "id": "group_1",
              "selected_option_id": "free-ship"
            }
          ]
        }
      ]
    }
  }
}
status ready_for_complete

{
  "status": "ready_for_complete",
  "totals": [
    {
      "type": "subtotal",
      "amount": 3500
    },
    {
      "type": "fulfillment",
      "amount": 0,
      "display_text": "Shipping"
    },
    {
      "type": "total",
      "amount": 3500
    }
  ]
}

What the agent knows now. ready_for_complete: nothing missing. $35.00 with free shipping.

7

Pay and place the order

dev.ucp.shopping.checkout

Only the payment, through a handler the store declared, and a fresh idempotency key so a retry cannot charge twice. This is the one call that places an order.

{
  "meta": {
    "ucp-agent": {
      "profile": "https://agent.example/.well-known/ucp"
    },
    "idempotency-key": "6f1c…"
  },
  "id": "01a14534-5475-…",
  "checkout": {
    "payment": {
      "instruments": [
        {
          "id": "instr_1",
          "handler_id": "mock_payment_handler",
          "type": "card"
        }
      ]
    }
  }
}
status completed, order NF-GKFVSO

{
  "status": "completed",
  "order": {
    "id": "01a14534-fc3c-…",
    "label": "NF-GKFVSO",
    "permalink_url": "https://flowers.ucpsandbox.com/orders/01a14534-fc3c-…"
  }
}

What the agent knows now. An order, with a page the buyer can open. Seven calls from a domain name to a paid order.

How far an agent gets today

Of the 19,780 verified stores we check, the share whose UCP profile declares each step of the run.

Steps a store declares

share of verified stores
Find products98.1%
Build a cart97.1%
Check out96%

Find products counts catalog.search or catalog.lookup. A store can declare checkout without a catalogue, when another surface sends the buyer.

How agents reach them

of the 19,399 that declare catalogue search
MCP98.4%
EMBEDDED55.8%
REST41.9%
A2A0%

A store can offer several transports; Embedded opens its checkout in the buyer's browser. Transports.

Try it on a store

Test the catalogue

Search a store's catalogue the way an agent does and check every product that comes back. Read-only, nothing is stored.

Check the profile

See whether a store declares catalogue search, cart and checkout, and which ways in an agent finds.

Questions

What is UCP product discovery?
How an agent finds what a store sells without reading its web pages. It fetches the store's UCP profile at /.well-known/ucp, checks that catalogue search is declared, and calls search_catalog on the endpoint the profile names. The store answers with typed products: ids, prices, variants, stock and images.
How is it different from a product feed or Google Shopping?
A feed is a copy of your catalogue sent to someone else's index, refreshed on their schedule. Discovery asks your store at the moment the buyer asks, so price and stock are current, and the same endpoint takes the cart and the checkout.
Which agents can do it?
Any agent with an MCP or REST client. MCP is the transport most stores declare: 98.4% of the verified stores we check that declare catalogue search offer it.
What does a store need to declare?
dev.ucp.shopping.catalog.search or dev.ucp.shopping.catalog.lookup for discovery. To go on and buy, an agent also needs cart or checkout and at least one payment handler. The capabilities page lists them all.
How do I know my product data is good enough?
Run the Catalog Validator on your store with a real search term. It makes the same calls as the run above and checks what comes back against 33 rules: ids, prices in minor units, variants, availability, images and descriptions.
Where do these numbers come from?
From the latest check of each verified store in the directory: what its UCP profile declares. A store that drops catalogue search leaves the count, and one that adds it joins.

Explore protocol data