— UCP

A3 turns any website into a UCP-compliant commerce endpoint.

The Universal Commerce Protocol gives agents one typed contract — discovery, negotiation, REST and MCP — for transacting with any business. But most suppliers don't expose a UCP API; they expose a website. A3 closes that gap: it learns each supplier's site into deterministic stages, then serves those flows behind a real UCP server.

— What UCP is

One protocol for agentic commerce.

UCP is an open specification for how platforms (agents) and businesses transact. It standardises capability discovery, version negotiation, transport bindings, and payments — so an agent can deal with any compliant business without a bespoke integration. These are the moving parts A3 has to satisfy.

"Hermes" — the commerce messenger.
01 · DISCOVERY

A profile at a well-known URL.

Every business publishes a profile at /.well-known/ucp declaring its protocol version, services, capabilities, and endpoints.

/.well-known/ucp
02 · NEGOTIATION

Server selects the intersection.

The platform advertises its profile per-request; the business intersects both capability sets and picks mutually-supported versions.

UCP-Agent
03 · CAPABILITIES

Reverse-domain names.

Features are named {domain}.{service}.{capability} — e.g. dev.ucp.hotels.deals — encoding governance without a central registry.

dev.ucp.*
04 · TRANSPORTS

REST and MCP, one contract.

The same operations are exposed over REST (OpenAPI) and MCP (JSON-RPC), so both classic clients and tool-calling agents can transact.

rest · mcp
05 · ENVELOPE

Every response carries ucp.

Responses include the negotiated version and active capabilities, plus structured messages and a continue_url fallback.

ucp envelope
06 · PAYMENTS

Decoupled payment handlers.

UCP separates payment instruments from handlers so credentials flow platform → business only, keeping intermediaries out of PCI scope.

handlers
— The gap A3 closes

Suppliers have websites, not UCP APIs.

UCP defines the contract an agent wants to call. The reality is that the vast majority of hotels, retailers, and travel suppliers will never ship a native UCP server. A3 stands in for them: it learns the live consumer site once, captures it as typed stages and a playbook, then replays those flows deterministically behind a UCP server — REST, MCP, discovery, and negotiation included.

"Atlas" — sites without UCP APIs.
POST /expedia-com/deals
UCP
# A typed UCP operation over REST or MCP
POST /expedia-com/deals
UCP-Agent: profile="https://agent.example/profile.json"

{
  "hotelId": "31558266",
  "checkIn":  "2026-09-14",
  "checkOut": "2026-09-17",
  "rooms": [{ "adults": 2 }]
}
runner replays learned stages
A3 runner
# No supplier API. A3 drives the real site:
1. negotiate capabilities from the agent profile
2. main stage builds the results URL + navigates
3. overlay-cookie dismisses the consent banner
4. room-results scrapes rooms, rates + checkoutIds
5. validate against the UCP schema, wrap in the ucp envelope
# deterministic — no LLM in the loop at runtime
One workflow per UCP operation. Stages are website states — not API methods. A3's hotels project ships a workflow for each capability (deals, checkout, book). Inside each, stages are named after what the page is (room-results, select-deal, guest-form), so site changes stay local and the UCP contract stays stable.
01 · OPERATIONS

Each UCP operation is one A3 workflow.

Operations are declared once as the single source of truth shared by both transports. An operation binds a UCP capability to a workflow path, a Zod schema, its REST route, and its MCP tool. Browser-backed operations run a workflow; lightweight ones (book/status, booking/details) read from an in-memory store with no browser.

capability
Reverse-domain UCP name, e.g. dev.ucp.hotels.deals.
workflow
Path to the A3 workflow the embedded runner plays back.
schema
Zod schema validating the inbound UCP request.
rest / tool
REST route and MCP tool — both delegate to the same operation.
toPayload
Maps workflow outputs into the UCP response body.
onSuccess
Side effects, e.g. cache a checkout or record a booking.
src/server/operations.ts
Configuration
{
  kind: 'workflow',
  capability: 'dev.ucp.hotels.deals',
  workflow: 'src/workflows/deals/HotelDeals.workflow.ts',
  schema: GetHotelDealsRequestSchema,
  rest: { method: 'POST', path: '/deals' },
  tool: {
    name: 'get_deals',
    description: 'Get available room deals and rates for a hotel and stay.',
  },
  toPayload: out => ({
    rooms: out.rooms ?? [],
    hotel: out.hotel,
    support: out.support,
  }),
}
02 · STATES → STAGES

The workflow is thin; the site lives in stages.

A UCP operation maps to a defineWorkflow with a typed input/output schema and a directory of per-supplier stages. The workflow itself carries almost no logic — it points at the schema and the sites directory. The real automation is learned into stages named after page states.

main
Builds the results URL from ctx.inputs and navigates directly.
overlay-cookie
Dismisses consent overlays; remembers the cookie for next run.
room-results
Scrapes rooms, rates, and a stable checkoutId per rate.
ctx.success()
Marks the terminal state once outputs validate against the schema.
src/workflows/deals/HotelDeals.workflow.ts
Configuration
export default defineWorkflow({
  title: 'UCP Hotels — Deals',
  description: 'dev.ucp.hotels.deals — scrape rooms and rates',
  inputsSchema: GetHotelDealsRequestSchema.shape,
  outputsSchema: GetHotelDealsResponseSchema.shape,
  rootDir: 'src',
  sitesDir: workflowSitesDir('deals'),
  projectLocations: ucpOperationProjectLocations(WORKFLOW_ROOT),
});
src/stages/expedia-com/deals/room-results.stage.ts
Learning output
export default defineStage({
  title: 'Room Results',
  description: 'Scrape room and rate deals from the hotel page',
  match: async (ctx) => {
    const url = new URL(ctx.page.url());
    if (!url.hostname.includes('expedia.com')) return false;
    return await ctx.page.evaluate(() =>
      !!document.querySelector('[data-stid^="property-offer-"]'));
  },
  run: async (ctx) => {
    const rooms = await ctx.page.evaluate(scrapeOffers);
    ctx.outputs.rooms = normalize(rooms);  // each rate has a checkoutId
    ctx.success();
  },
});
03 · DISCOVERY

A real /.well-known/ucp profile.

The server builds a business profile per supplier site, advertising the hotels service over both REST and MCP and listing the capabilities it implements. Every path is prefixed with the supplier slug (e.g. expedia-com), so one server can front many suppliers — each fully discoverable.

version
The UCP protocol version the business processes requests at.
services
dev.ucp.hotels bound to REST and MCP endpoints.
capabilities
deals, checkout, book with spec + schema URLs.
spec origin
Spec URLs resolve to ucp.dev, matching the namespace authority.
GET /expedia-com/.well-known/ucp
Configuration
{
  "ucp": {
    "version": "2026-04-08",
    "services": {
      "dev.ucp.hotels": [
        { "transport": "rest", "endpoint": "…/expedia-com" },
        { "transport": "mcp",  "endpoint": "…/expedia-com/ucp/mcp" }
      ]
    },
    "capabilities": {
      "dev.ucp.hotels.deals":    [{ "version": "2026-04-08", "spec": "https://ucp.dev/…" }],
      "dev.ucp.hotels.checkout": [{ "version": "2026-04-08", "spec": "https://ucp.dev/…" }],
      "dev.ucp.hotels.book":     [{ "version": "2026-04-08", "spec": "https://ucp.dev/…" }]
    }
  }
}
04 · TRANSPORTS

REST and MCP from one operation.

Both transports delegate to the same UcpService, which validates input, negotiates capabilities, runs the workflow, and returns a UCP envelope. REST routes by method and path; MCP exposes each operation as a tool, with input nested under the capability's short domain key.

REST
POST /<site>/deals with the UCP-Agent header.
MCP
tools/call with get_deals and a nested deals argument.
negotiation
Profile fetched from the header, cached, and intersected before any run.
serialised runs
Runs for a site share one browser session, executed in order.
terminal
curl
curl -X POST http://localhost:3004/expedia-com/deals \
  -H 'Content-Type: application/json' \
  -H 'UCP-Agent: profile="https://agent.example/profile.json"' \
  -d '{ "hotelId": "31558266", "checkIn": "2026-09-14",
       "checkOut": "2026-09-17", "rooms": [{ "adults": 2 }] }'
POST /expedia-com/ucp/mcp
tools/call
{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "get_deals",
    "arguments": {
      "meta": { "ucp-agent": { "profile": "https://…" } },
      "deals": { "hotelId": "31558266", "rooms": [{ "adults": 2 }] }
    }
  },
  "id": 1
}
05 · DATA FLOW

Operations chain by semantic handles.

The three browser workflows compose into a full booking. A rate's checkoutId flows from deals into checkout and book; book returns a bookingId that the server-only status and details operations read from an in-memory store. Only semantic payload crosses the boundary — never internal browser session tokens.

checkoutId
Produced by deals (per rate); consumed by checkout + book.
bookingId
Produced by book; consumed by status + details (no browser).
booking pipelinechained handles
1deals → rooms[].rates[].checkoutIdbrowser
2checkout(checkoutId) → price breakdownbrowser
3book(checkoutId, guest, payment) → bookingIdbrowser
4book/status · booking/details(bookingId)store
Negotiation gates every run. Platforms advertise a profile via UCP-Agent; the server fetches and caches it, checks the protocol version, and intersects capabilities before any browser session starts — returning capabilities_incompatible or version_unsupported when they don't match.
— Go deeper

UCP is the contract. A3 makes any site fulfil it.

Read the UCP specification for the protocol details, then explore A3's stage-based model to see how learned, deterministic flows stand in for missing supplier APIs.

UCP spec ↗ A3 concepts