Skip to main content
Glama
README.md
# UCP Shopping Agent

A minimal agent that connects to a Shopify store's [UCP](https://ucp.dev) (Universal Commerce
Protocol) MCP endpoint and drives search → cart → checkout — either via CLI flags or a
conversational chat REPL powered by Claude.

## How it works

- The store's `ucp.json` (`.well-known/ucp` manifest) declares an MCP endpoint for shopping.
- This agent connects to that endpoint, discovers its tools (`search_catalog`, `create_cart`,
  `create_checkout`, `complete_checkout`, ...), and calls them directly.
- Every call carries a `ucp-agent` reference pointing at this agent's own **profile** —
  a small JSON file ([public/agent-profile.json](public/agent-profile.json)) declaring which
  capabilities (cart, checkout, catalog search) it supports. The store fetches that profile to
  decide what to allow, so it must be reachable at a public HTTPS URL.

## Setup

1. Install dependencies:
   ```bash
   npm install
   ```
2. Copy `.env.example` to `.env` and fill in the values (see below).
3. Serve the agent profile locally:
   ```bash
   npm run serve:profile
   ```
4. Expose it publicly with a tunnel (Cloudflare Tunnel is recommended — ngrok's free tier
   injects a browser-warning interstitial that breaks server-to-server profile fetches):
   ```bash
   cloudflared tunnel --url http://localhost:8787
   ```
   Copy the resulting `https://*.trycloudflare.com` URL, append `/agent-profile.json`, and set it
   as `AGENT_PROFILE_URL` in `.env`.

### Environment variables (`.env`)

| Variable | Required | Purpose |
|---|---|---|
| `AGENT_PROFILE_URL` | Yes | Public URL serving `public/agent-profile.json` (step 4 above). |
| `ANTHROPIC_API_KEY` | Only for `npm run chat` | Powers the conversational agent. |
| `CLIENT_ID` / `CLIENT_SECRET` | No | Only needed for a *different* audience (e.g. Shopify's global catalog service via `--use-client-credentials`) — this store's own MCP endpoint doesn't require a bearer token. |
| `BUYER_COUNTRY` | No (default `US`) | Sent as `context.address_country` on cart/checkout calls. Without a country, the store geolocates the request's IP and can report real inventory as "out of stock" if no location ships there. |

## Usage

**Scripted (CLI flags):**
```bash
npm run start -- --query "snowboard"                        # search + cart (safe, default)
npm run start -- --query "snowboard" --checkout              # + create a checkout
npm run start -- --query "snowboard" --checkout --pay --payment-token TOKEN   # + complete it
```

**Conversational (Claude-driven chat):**
```bash
npm run chat
```
```
You: search for a snowboard
Agent: [lists real products with prices]
You: add the first one to my cart
Agent: [adds it, or tries other variants if one's out of stock]
```

Checkout/payment completion always requires an explicit request and a real payment credential —
the agent never fabricates a payment token.

## Project layout

- [src/manifest.ts](src/manifest.ts) — parses `ucp.json`, resolves the MCP endpoint.
- [src/ucpClient.ts](src/ucpClient.ts) — thin MCP SDK wrapper for the shopping tools.
- [src/auth.ts](src/auth.ts) — optional `client_credentials` bearer token fetch.
- [src/index.ts](src/index.ts) — scripted CLI flow.
- [src/agent.ts](src/agent.ts) — conversational chat agent (Claude tool-use loop).
- [scripts/serve-profile.mjs](scripts/serve-profile.mjs) — serves `public/agent-profile.json` locally.

Maintenance

ActivityMaintained
ResponsivenessNo issues