UCP Checker
for agents and developers

API & MCP documentation

Check any domain for Universal Commerce Protocol support, find the stores an agent can actually transact with and search their live catalogues, then shop at the store directly — from the independent record that re-checks every verified store daily. Read-only and keyless.

v1.0.0| Base URL: https://ucpchecker.com| JSON Schema| ard.json| server-card.json| llms.txt

Quickstart

Add the UCP Checker MCP server to any MCP-capable agent. It gets check-domain, list-stores, search-all and five more tools in its tray; resolving a store to buy from is four calls.

terminal
claude mcp add --transport http ucp-checker https://ucpchecker.com/mcp
~/.cursor/mcp.json
{
    "mcpServers": {
        "ucp-checker": {
            "url": "https://ucpchecker.com/mcp"
        }
    }
}
claude_desktop_config.json
{
    "mcpServers": {
        "ucp-checker": {
            "type": "streamable-http",
            "url": "https://ucpchecker.com/mcp"
        }
    }
}
Settings → Connectors → Create
https://ucpchecker.com/mcp
.vscode/mcp.json
{
    "servers": {
        "ucp-checker": {
            "type": "http",
            "url": "https://ucpchecker.com/mcp"
        }
    }
}

That is the whole setup. What the server exposes is under MCP server; no MCP client, use the REST API or ARD search.

CLI

No agent, no MCP client — just a terminal or a CI job. ucp-check is a zero-dependency Node client over the REST API below: it renders the verdict the API returns and turns it into an exit code. It never scores locally, so a check from CI says exactly what the status page says.

terminal
npx ucp-check your-store.com
ExitMeaning
0verified
1not verified — not_detected, invalid, blocked, unreachable, pending
2usage error
3API unreachable or rate limited

--cached reads the last observed state without crawling (use it on every push; run the live check on deploy), --json prints the response as served, --quiet is exit-code only. Source and issues: github.com/ucpchecker/ucp-check · npm.

MCP server

One streamable-HTTP server at https://ucpchecker.com/mcp. It exposes the 8 tools documented below, read straight from the server class so this page cannot drift from what it serves. Read-only tools are open at every tier; the cart tools are for signed or token callers once enforcement is on. The server also publishes a machine-readable card at /.well-known/mcp/server-card.json.

The resolution flow — list-stores (or search-all) → search-catalog → get-product-details → search-policies, then discover-store to see what the merchant itself exposes. There is no server-side session. UCP Checker is read-only: it resolves and measures, it never carts, checks out or takes payment — you transact with the merchant.

Authentication & rate limits

Every read endpoint is open: no API key, no signup. Limits are per IP and per tier:

TierHowMCP callssearch-all
anonymousNothing — just connect30/min · 2,000/day12/min
signedSign requests with Web Bot Auth (RFC 9421); we resolve your Signature-Agent key directory120/min20/min
tokenAuthorization: Bearer <key> — keys are issued to partners on request300/min60/min

REST: POST /api/v1/check is 30/min and 200/day per IP (it crawls); other endpoints 60/min and 1,000/day. ARD endpoints share the REST limiter. Over the limit you get 429 with Retry-After. Our own outbound requests are signed too — verify them against /.well-known/http-message-signatures-directory.

Guide — build a shopping agent

The minimum viable agent is six steps. With the MCP server connected, steps 1–5 are single tool calls; without it, the same flow works against any store's own UCP profile and MCP endpoint. The long-form version, with code, is at /agents.

#StepHow
01Pick a target storeUse list-stores (or POST /ard/search) for a verified store with an MCP transport and a high score — or browse the directory.
02Fetch its UCP profileGET https://{domain}/.well-known/ucp. check-domain does this for you and returns status, version, capabilities and transports.
03Parse capabilities and the MCP endpointThe profile's services block names the transport and endpoint; capabilities tell you whether cart and checkout are declared. discover-store lists the live tools.
04Connect an MCP clientStreamable HTTP to the endpoint the profile declares — never a guessed path. UCP binds the tool names (search_catalog, lookup_catalog, get_product) and every tool call carries meta["ucp-agent"] naming your platform profile. Most read tools are public; some stores gate write tools behind auth.
05Search the cataloguesearch-catalog (one store) or search-all (the fleet) return titles, prices and variant IDs; get-product-details returns a product's full declared detail.
06Hand off to the merchantUCP Checker is read-only: it resolves and measures, it never carts or checks out. Once you have picked a store, transact with that store's own endpoint.

To test the whole journey against a live store with a real model — every tool call recorded — use the UCP Playground.

Guide — methodology & the UCP score

Every verified store is re-checked daily from the outside in: we fetch its profile as an agent would, validate it against the current spec, read its bot policies and surface signals, and record what we observed. The score summarises that record. The full method — crawler behaviour, response classification, validation rules, refresh schedule — is on the methodology page; this is the part you need to read a number.

Score = weighted average of three categories, each 0–100
CategoryWeightWhat it measures
discovery
Agent Discovery
30%Can agents find and reach this store? HTTPS on the profile endpoint, reachability, an agent-friendly robots.txt, and surface signals such as llms.txt and a sitemap.
conformance
UCP Conformance
40%Does the profile validate against the spec? Validity is weighted 3× — an invalid profile cannot score above ~50 here. Declaring a known spec version and clean required fields count.
capabilities
Capability Coverage
30%What can an agent actually do here? Declared transports (REST / MCP / A2A), checkout, payment handlers, and breadth of capabilities; functional probes raise it when they pass.

score = discovery × 0.30 + conformance × 0.40 + capabilities × 0.30 , rounded to the nearest integer. A blocked or unreachable store scores 0 on discovery; an undetected profile caps it.

Grade bands
GradeScoreReads as
A85–100Agent-ready — valid profile, strong discovery, broad capability coverage
B70–84Solid — minor warnings or one weak category; agents can still transact
C50–69Partial — profile works but missing capabilities or surface signals
D30–49Weak — profile reachable but invalid or near-empty
F0–29Failing — blocked, unreachable, or no profile detected

The score is a summary of observed conformance, not a ranking and not a trust rating. In ARD results it travels as metadata.ucpScore, deliberately separate from the relevance score.

Guide — score model versioning

A reading is only useful if today's number means the same thing as last quarter's. So the score model is versioned, history is never rescored, and every number says which model produced it. Drift is not forbidden — unlabelled drift is.

Two independent version axes
AxisVersionsCurrentConsumer rule
contractThe shape of an API response — which fields exist and what they meanv1.0.0Pin the MAJOR
modelHow the score was computed — weights, grade bands, category definitions, the check setv1.0.0 (since 2026-08-25)Compare only within a MAJOR
Model SemVer
BumpWhenComparable?
MAJORWeights, grade bands or category definitions changeNo — scores are not comparable across a major
MINORA check is added, removed or retuned inside a categoryYes, frame holds; the series is annotated at the boundary
PATCHThe model now computes what it always intended (a check that silently never fired)Yes, flagged
Contract SemVer

MAJOR — a stable field is removed, renamed or changes meaning. MINOR — anything additive, including check-catalogue membership. PATCH — documentation or spec-only corrections. Stable within a major: domain, status, score, grade, category_scores keys, check ids, model_version, contract_version.

Hard rules

Never rescore history. A point in the series reflects the model in force when it was observed; backfilling today's model onto old dates would assert scores merchants never had. Announce every model change on the blog and the methodology page before it ships. Gate CI on check ids or a threshold, not on "all required checks pass" — the required set can grow on a minor.

Check & resolve

check-domainread-only
Check if a domain supports Universal Commerce Protocol (UCP). Returns the UCP status, manifest version, capabilities, response latency, and AI bot access policies (GPTBot, ClaudeBot, Google-Extended, etc.). If the store's edge rate-limits the live attempt, the result says so and reports the last OBSERVED state and when it was observed — an unobserved attempt is never presented as a verdict about the store. The domain is automatically normalized (removes protocol, www, paths). Examples: "shopify.com", "https://www.example.com/path" → "example.com" A negative result is information, not permission. It reports what UCP Checker has observed — it does not say a store cannot be used, and it is not a reason to stop. If a store matters to your task, try discover-store or connect to it directly regardless of what this returns.
Parameters
NameTypeDescription
domainrequiredstringThe domain to check for UCP support (e.g., "shopify.com", "example.com"). Protocol, www prefix, and paths are automatically removed.
list-storesread-only
List verified UCP storefronts across every platform, best-evidenced first. Use when the user wants to browse stores — e.g., "what stores can I shop at?" or "show me Wix stores". To find stores that sell something, prefer search-all. Each store carries what we have actually observed about it, not what it claims: - `transactable` — declares checkout and we have read its catalogue - `catalogued` — we have read its catalogue - `resolvable` — its endpoint resolves, we have not probed it yet - `declared` — a valid manifest, nothing observed beyond it Filter by `platform` (shopify, wix, woocommerce, bigcommerce, shopware…). `category` narrows to the smaller set of deeply audited stores (see list-categories), so leave it out unless the user asks for a category. Developer previews and staging hosts are not listed.
Parameters
NameTypeDescription
platformstringRestrict to one platform, e.g. "wix", "shopify", "woocommerce".
categorystringOptional. Limit to the deeply audited stores in one category (e.g., "footwear"); see list-categories. Most browsing is better without it.
limitintegerMaximum number of stores to return (default: 10, max: 50)
list-categoriesread-only
List store categories with store counts. Categories exist only for the deeply audited subset of verified stores, so this is a way to browse, not the whole index: list-stores and search-all cover every verified storefront. Sorted by number of stores (most first).
Parameters

None.

discover-storeread-only
Discover available shopping tools on a UCP-enabled store. Connects to the store's MCP endpoint and lists all available tools (search, cart, shipping, etc.). Use this to understand what a store supports before shopping. Example: domain: "allbirds.com"
Parameters
NameTypeDescription
domainrequiredstringThe store domain to discover (e.g., "allbirds.com")

Read catalogs & policies

search-catalogread-only
Search for products on any UCP-enabled Shopify store. Searches the store's live product catalog via UCP/MCP and returns matching products with titles, prices, variants, and images. Examples: - domain: "allbirds.com", query: "tree topper" - domain: "gymshark.com", query: "hoodie"
Parameters
NameTypeDescription
domainrequiredstringThe store domain (e.g., "allbirds.com", "gymshark.com"). Must be a UCP-enabled Shopify store.
queryrequiredstringProduct search term (e.g., "tree topper", "wool runners", "hoodie")
countrystringISO country code for localized pricing/inventory (e.g., "US", "GB", "CA"). Optional — defaults to store default.
search-allread-only
Search for products across verified UCP stores at once. Fans the query out, concurrently, to the stores whose observed catalogue best matches it, and returns results grouped by store with each store's UCP score and evidence. Rare query words count for more than common ones. If no store's catalogue matches well enough, it searches no one and says "No strong match", naming the words no store carries and the closest weak matches, so you can go to a store you know instead of rewording. Slow or failing stores are skipped. `category` narrows the fan-out to the smaller set of deeply audited stores; leave it out for most queries. Example: query: "mattress topper", maxStores: 5
Parameters
NameTypeDescription
queryrequiredstringProduct search term (e.g., "running shoes", "hoodie")
categorystringOptional. Limit the fan-out to the deeply audited stores in one category (e.g., "footwear"); see list-categories. Most queries search better without it.
countrystringISO country code for localized pricing (e.g., "US", "GB"). Optional.
maxStoresintegerMaximum number of stores to search (default: 5, max: 10)
get-product-detailsread-only
Get full product details including variant IDs from a UCP-enabled store. Use after search-catalog to see a product's full declared detail, including its variants. Pass the Product ID from search results to get all variants with their IDs. Example: domain: "allbirds.com", productId: "gid://shopify/Product/123456"
Parameters
NameTypeDescription
domainrequiredstringThe store domain (e.g., "allbirds.com")
productIdrequiredstringThe product ID from search-catalog results (e.g., "gid://shopify/Product/123456")
search-policiesread-only
Search store policies on any UCP-enabled Shopify store. Query return policies, shipping policies, refund policies, privacy policies, terms of service, or any other store policy. Returns the matching policy text. Use this when a user asks about a store's policies before or after purchase — e.g., "what is the return policy?", "do they offer free shipping?", "refund window?" Example: domain: "allbirds.com", query: "return policy"
Parameters
NameTypeDescription
domainrequiredstringThe store domain (e.g., "allbirds.com")
queryrequiredstringPolicy search term (e.g., "return policy", "shipping", "refund window", "privacy policy")

Discovery — Agentic Resource Discovery

UCP Checker is an ARD v0.91 discovery service — the federated standard agents use to ask "what's available for this task?" before invoking anything. Every result is a verified storefront as a standard catalogue entry: identifier (urn:air:{domain}:ucp:storefront), url (the store's /.well-known/ucp), capabilities, metadata (category, platform, grade, ucpScore, mcpEndpoint) and a trustManifest whose attestations link the store's public conformance record. Ask for type: ["application/mcp-server-card+json"] and stores with an MCP endpoint come back as inline server cards.

POST/ard/search
Find verified storefronts for a natural-language need

Agentic Resource Discovery §5.3.2. Returns ARD catalogue entries — one per verified store — each with the store's UCP profile URL, declared capabilities, MCP endpoint and a trustManifest linking its public conformance record. Ranking is lexical and deterministic: each query word counts by how rare it is across the index (a word few stores carry says more than one most do), a category synonym counts at 0.7 of a direct match, singular and plural match each other, accented letters match their base letters, and the query as a phrase in a store's name is a full match. Stores scoring below 30 are not returned, so an empty `results` list means no strong match — try the product type alone, or go to a store you know. Equal scores are ordered by how prominent the query words are on the store's observed shelf, then evidence, then UCP score, then own domain before platform subdomain. A query reaches its first 50 results. `score` is relevance only; the UCP score is in `metadata.ucpScore`.

Parameters
NameInTypeDescription
query.textrequiredbodystringWhat the agent needs, e.g. "running shoes".
query.filterbodyobjectField → array of values. Supported: type, tags, capabilities, publisher, metadata.category, metadata.platform, metadata.country, metadata.grade, metadata.tier, metadata.transports, metadata.evidence, trustManifest.identityType, trustManifest.attestations.type. Unknown fields → 400.
federationbodystringauto (default) | referrals | none. We do not proxy upstream; auto and referrals return the GitHub and Hugging Face finders as referrals.
pageSizebodyintegerDefault 10, max 100 (larger values are capped). Pages stop at the first 50 results.
pageTokenbodystringFrom the previous response.
curl
curl -s -X POST https://ucpchecker.com/ard/search \
  -H 'Content-Type: application/json' \
  -d '{"query": {"text": "running shoes",
              "filter": {"metadata.platform": ["shopify"]}},
       "federation": "none", "pageSize": 5}'
Responses
200{ results: [entry + score + source], referrals?, pageToken? } — results may be empty (no strong match)400INVALID_ARGUMENT — missing text, body not a JSON object, unsupported filter field, bad token405METHOD_NOT_ALLOWED — search is POST429RATE_LIMIT_EXCEEDED — honour Retry-After
POST/ard/explore
Facet counts over the matched set

ARD §5.3.3. Same query model as search, including the relevance floor; returns bucket counts over the matched stores for the requested fields instead of entries — "which categories are there?", "how many stores per platform?". Without query text, counts cover every listed store.

Parameters
NameInTypeDescription
querybodyobjecttext and/or filter, as for search.
resultType.facets[]requiredbodyarray{ field, limit?, minCount? } — field from the supported list.
curl
curl -s -X POST https://ucpchecker.com/ard/explore \
  -H 'Content-Type: application/json' \
  -d '{"resultType": {"facets": [{"field": "metadata.category", "limit": 10},
                                {"field": "metadata.platform"}]}}'
Responses
200{ resultType: "facets", facets: { field: { buckets: [{value, count}], otherCount? } } }400INVALID_ARGUMENT — missing resultType.facets, unsupported field, body not a JSON object429RATE_LIMIT_EXCEEDED — honour Retry-After
GET/ard/agents
Deterministic, cacheable browse

ARD §5.3.4. No relevance ranking — sorted, filtered, paged. Built for developer portals and crawlers. Pages stop at the first 50 entries; the index is browsable, not exportable. Responses are cached at the edge for up to 15 minutes, so a store verified a moment ago may take that long to appear.

Parameters
NameInTypeDescription
filterquerystringEBNF-lite, e.g. type = 'application/mcp-server-card+json' AND updatedAfter > '2026-01-01'. Fields: displayName, type, publisherId, createdAfter, updatedAfter.
orderByquerystringdisplayName | updatedAt, optionally ASC|DESC.
pageSizequeryintegerDefault 20, max 100.
pageTokenquerystringFrom the previous response.
curl
curl -s "https://ucpchecker.com/ard/agents?pageSize=20&orderBy=updatedAt%20DESC"
Responses
200{ items: [entry], total, pageToken? }400INVALID_ARGUMENT — malformed filter or orderBy, or a pageToken past the result limit429RATE_LIMIT_EXCEEDED — honour Retry-After

REST API

The same record over plain HTTP. All responses are JSON; the request and response shapes are published as JSON Schema at /api/v1/schema.

Observed, not asserted. Every record carries two timestamps: observed_at — when we last actually saw the store (any status) — and attempted_at — when we last tried. outcome says what the latest attempt told us; only observed refreshes status. When a store's edge rate-limits our crawler the attempt is recorded, observed is false, and the record you get is the last observation, not a new verdict. Treat observed_at as the freshness of the data.

POST/api/v1/check
Run a fresh live check of a domain's UCP profile

Fetches and validates /.well-known/ucp right now, records the result, and returns the domain's status. Use GET /api/v1/status/{domain} when you only need the current record. If the store's edge rate-limits the attempt the response is still 200: `observed` is false, `status` and every other field are the last observed state, and a Retry-After header (and `retry_after_s`) says when to try again — an attempt that observed nothing never changes a verdict.

Parameters
NameInTypeDescription
domainrequiredbodystringDomain to check, e.g. "example.com". Scheme, www and path are stripped.
curl
curl -s -X POST https://ucpchecker.com/api/v1/check \
  -H 'Content-Type: application/json' \
  -d '{"domain": "allbirds.com"}'
Responses
200merchant_status — { data: { domain, status, ucp_version, manifest_url, observed_at, attempted_at, outcome, observed, retry_after_s, last_checked_at } }422Invalid domain429Rate limited — 30/min, 200/day per IP; Retry-After set
GET/api/v1/status/{domain}
The current record for a domain

What we last observed: status, declared UCP version, the profile URL, and when it was observed (`observed_at`). `attempted_at` and `outcome` say whether a more recent attempt observed nothing (for example, the store's edge rate-limited us) — `observed: false` means the record is older than the last attempt. No crawl is triggered.

Parameters
NameInTypeDescription
domainrequiredpathstringBare domain, e.g. "allbirds.com".
curl
curl -s https://ucpchecker.com/api/v1/status/allbirds.com
Responses
200merchant_status404Never checked — POST /api/v1/check first42960/min, 1,000/day per IP
GET/api/v1/schema
JSON Schema for every request and response above

Draft 2020-12. The same schema is declared as the com.ucpchecker.api service in our own /.well-known/ucp, so conformance tooling can resolve it.

curl
curl -s https://ucpchecker.com/api/v1/schema
Responses
200JSON Schema document

Skills

Self-contained instruction documents for coding agents, served live at /.well-known/agent-skills/index.json (with sha256 digests) so the current spec version never bakes into an agent's memory. Paste the URL into your agent, or fetch it over MCP as a resource.

ucp-agent-readyskill-md
Make a store agent-ready with UCP

Publish or repair a Universal Commerce Protocol (UCP) profile so AI shopping agents can discover, read and transact with a store, verified against UCP Checker's independent validator. Use when asked to "make this store agent-ready", "add UCP", "fix our /.well-known/ucp", "improve our UCP score", or when a UCP check reports errors or warnings. Drives a check → fix → re-check loop over the keyless UCP Checker API.

SKILL.md
https://ucpchecker.com/.well-known/agent-skills/ucp-agent-ready/SKILL.md
ucp-checkerskill-md
Resolve verified UCP stores with UCP Checker

Find stores an AI agent can actually transact with, and check any domain's Universal Commerce Protocol (UCP) status, using the UCP Checker resolver. Use when choosing a store that supports agentic checkout, checking whether a merchant is agent-ready, or comparing stores by UCP conformance. Read-only: it resolves and measures, it never carts or checks out. Designed for agents evaluating merchants before acting.

SKILL.md
https://ucpchecker.com/.well-known/agent-skills/ucp-checker/SKILL.md

Well-known files

Everything an agent needs to discover and verify this server without being told about it.

Errors

ARD errors follow the spec's error object — a top-level errorCode and message — and every failure under /ard, including the ones the server raises itself, is JSON: { "errorCode": "INVALID_ARGUMENT", "message": "…", "error": { "code": "INVALID_ARGUMENT", "message": "…" } }. The nested error object is the shape this endpoint shipped with; it stays for existing clients, and new ones should read errorCode.

HTTPWhereMeaning
400ARDINVALID_ARGUMENT — missing query.text, a body that is not a JSON object, unsupported filter/facet field, bad pageToken (or one past the 50-result limit), bad orderBy.
404ARDNOT_FOUND — no such ARD endpoint; the profile is at /.well-known/ard.json.
405ARDMETHOD_NOT_ALLOWED — e.g. GET /ard/search; search and explore are POST.
404RESTDomain never checked — run POST /api/v1/check.
422RESTValidation failed (not a domain).
429allRate limited; honour Retry-After. On ARD the code is RATE_LIMIT_EXCEEDED.
500ARDINTERNAL_ERROR — nothing about the failure is exposed in the message.
MCPtoolsTool errors come back as an isError result with a plain-language message — an unknown tool name is a JSON-RPC error, not a 500.

Versioning

The API contract is v1.0.0. The REST response envelope and the MCP tool names are stable within a major version; new tools and new optional fields are additive. The UCP score model is versioned separately from the API — a score change is a model change, never a silent one, and is announced on the blog and in the methodology. Nothing is removed without notice.

Changes
DateChange
2026-09-15Removed: the MCP ucp://stores/verified resource. Use list-stores to browse (up to 50, filter by platform), search-all or POST /ard/search to find stores. POST /ard/explore no longer facets on publisher (it is still a filter).
2026-09-01Additive: observed_at, attempted_at, outcome, observed, retry_after_s on merchant_status (REST), observed_at on the MCP ucp://stores/verified resource, ARD updatedAt now the last observation, last_observed_at + last_outcome columns appended to the CC-BY dataset. last_checked_at is kept as an alias of observed_at. POST /api/v1/check sends Retry-After when the live attempt observed nothing.

Where it's listed