Back to Build
Engineering · 12 min read

Building a UCP/MCP gateway for agentic commerce

How to let any MCP-compatible AI agent (Claude, ChatGPT, Cursor, Gemini via Vertex, custom internal tools) discover, search, cart, check out, and pay on your platform through the Universal Commerce Protocol. With concrete architecture, tool definitions, and the failure modes we've hit in production.

TL;DR

UCP defines what commerce capabilities a store exposes (discover, catalog, cart, checkout, payment). MCP defines howan agent talks to a tool server. A UCP/MCP gateway is the bridge: it terminates MCP from the agent, translates each call into UCP operations against the merchant's server, and streams results back. Done right, the agent never knows it's talking to a gateway. It just sees a clean set of commerce tools.

Why a gateway?

UCP is the protocol merchants implement. MCP is what agent platforms speak natively today: Claude Desktop, ChatGPT's app connectors, Cursor, and any custom agent built on the Anthropic or OpenAI SDKs. If your platform sits between buyers (using agents) and merchants (running UCP), you have three options:

  1. Direct UCP: make every agent speak UCP. Doesn't happen; agents speak MCP.
  2. Per-merchant MCP servers: every merchant runs an MCP endpoint alongside UCP. Most won't.
  3. Gateway: you expose one MCP server that fronts UCP for every merchant you support.

Option 3 is the only realistic shape for a platform-side play. It lets you bring agentic shopping to thousands of stores without each store needing to do anything extra beyond their existing UCP implementation.

Architecture

The gateway has four moving parts:

┌─────────────┐    MCP/SSE    ┌─────────────────┐    UCP/HTTPS    ┌────────────────┐
│   Agent     │  ───────────▶ │  UCP/MCP        │  ─────────────▶ │  Merchant UCP  │
│  (Claude,   │  ◀─────────── │   Gateway       │  ◀───────────── │  endpoint(s)   │
│  ChatGPT…)  │               │                 │                 │  (n merchants) │
└─────────────┘               └─────────────────┘                 └────────────────┘
                                       │
                                       ▼
                              ┌─────────────────┐
                              │ Merchant         │
                              │ registry +       │
                              │ session store    │
                              └─────────────────┘
  1. MCP transport: speaks JSON-RPC over SSE (Server-Sent Events) or stdio, depending on how the agent connects.
  2. Tool registry: exposes a fixed set of commerce tools to the agent. The ones you'll need are search_products, get_product, create_cart, update_cart, create_checkout, update_checkout, and complete_checkout.
  3. UCP client: for every tool call, this resolves which merchant to dispatch to, fetches their /.well-known/ucp profile, and calls the right operation.
  4. Session store: caches discovery results, holds cart and checkout state across tool calls within an agent session.

The tool surface

Keep the surface narrow. Each MCP tool maps 1:1 onto a UCP operation, with merchant context resolved inside the gateway:

// Tool: search_products
{
  "name": "search_products",
  "description": "Search a merchant's catalog. Returns products with variants and pricing.",
  "inputSchema": {
    "type": "object",
    "required": ["merchant", "query"],
    "properties": {
      "merchant": { "type": "string", "description": "Merchant domain, e.g. jbhifi.com.au" },
      "query":    { "type": "string" },
      "limit":    { "type": "integer", "default": 20 }
    }
  }
}

// Tool: create_cart
{
  "name": "create_cart",
  "description": "Create a cart with one or more product variants for a specific merchant.",
  "inputSchema": {
    "type": "object",
    "required": ["merchant", "line_items"],
    "properties": {
      "merchant": { "type": "string" },
      "line_items": {
        "type": "array",
        "items": {
          "type": "object",
          "required": ["item", "quantity"],
          "properties": {
            "item":     { "type": "object", "properties": { "id": { "type": "string" } } },
            "quantity": { "type": "integer", "minimum": 1 }
          }
        }
      },
      "context": {
        "type": "object",
        "properties": { "address_country": { "type": "string", "default": "AU" } }
      }
    }
  }
}

Resolving the merchant

Every tool call carries a merchant string. Inside the gateway:

  1. Normalise the domain (strip https://, trailing slashes, www.).
  2. Look up the merchant's UCP profile from cache; if not cached, GET https://<merchant>/.well-known/ucp and store the negotiated services.dev.ucp.shopping endpoint, supported capabilities, and payment handlers.
  3. Dispatch the operation to that endpoint using the discovered transport (today: HTTPS JSON-RPC).
  4. Cache profile for 1 hour. Re-fetch on 404/410 or when a tool call returns a schema-validation failure that suggests the profile drifted.

Session state

Agents call tools one at a time. The state that matters lives in cart_id and checkout_id values that get returned from one call and need to be passed into the next. There are two ways to handle this:

  • Stateless - let the agent track cart_id in its conversation memory and pass it as a parameter on subsequent tool calls. Simple, scales horizontally, works fine if your agents are good at threading IDs.
  • Stateful - store a session keyed on (agent_session_id, merchant) and remember the cart/checkout context server-side. Agents only need to pass merchant; the gateway knows which cart they're working in.

We've found stateful to be worth the extra plumbing - agents make smaller mistakes when they don't have to track opaque IDs across turns.

The checkout cliff

Search, cart, and checkout-create are the easy part. complete_checkoutis where most gateways stall, and it's where UCP has the most platform-specific behaviour.

On Shopify-backed merchants you'll see two patterns:

  • requires_escalation: the checkout is created but payment requires a buyer-authenticated JWT (Google Pay or Shop Pay token). Without one, you can't complete the purchase programmatically. The gateway should hand the agent back a continue_url so the buyer can finish in a browser.
  • extension_interaction_required: Shopify Checkout Extensibility components (terms acceptance, age gating, custom consent, shipping selectors rendered as UI extensions) cannot be driven via the protocol. Surface this to the agent as a hand-off, not as a hard failure.

Build both as first-class outcomes of complete_checkout, not as errors. From the agent's perspective, "buyer needs to finish at this URL" is a successful tool call - it just isn't the end of the purchase.

Production hardening

  • Idempotency - every cart/checkout mutation should carry an idempotency key, so retries from a flaky agent don't create duplicate orders.
  • Timeouts - UCP calls can be slow during checkout. Give merchant calls a 10s timeout and surface timeouts to the agent as "temporary" rather than "failed" so it retries.
  • Rate limits - both inbound (per-agent) and outbound (per-merchant). The biggest blast radius is a misbehaving agent that hammers search_products.
  • Capability gating - at discovery time, only expose tools the merchant's UCP profile actually supports. Some merchants will lack lookup_catalog; don't advertise it.
  • PII handling - addresses and contact details flow through your gateway. Treat them as you would a payment processor: encrypted at rest, redacted from logs, retention policies in place.

What this unlocks

Once your gateway works against one merchant, it works against any UCP-compliant merchant on day one. That's the whole point of protocols. You get:

  • An agentic shopping surface that any MCP-compatible client can consume - Claude Desktop, ChatGPT, Cursor, custom internal tools.
  • Coverage that grows automatically as Shopify and other platforms roll out UCP across their merchants.
  • A clean separation between your agent layer and the merchant layer - meaning you can swap LLMs, change platforms, or pivot the UX without touching commerce plumbing.

Building a UCP/MCP gateway? Let's chat.

We've shipped UCP-native agents in production. Happy to compare architecture notes, talk through the gotchas, or walk through what your gateway should look like. Free consultation.