Guides
Tutorial: ship a UCP-compliant commerce MCP server to every agent host with one command#
In this tutorial you wrap a Universal Commerce Protocol (UCP) MCP server in an agent-connector package and install it into every agent host on your machine with one command. The server is Shopify's public Global Catalog endpoint, so there is nothing to deploy first; the same steps apply to a UCP server you run yourself.
Before you start: UCP in MCP terms#
The Universal Commerce Protocol lets a business declare commerce capabilities (catalog search, checkout, fulfillment, discounts, orders) in a profile at /.well-known/ucp and offer them over REST, MCP, A2A or an embedded protocol. The MCP binding is plain MCP: tools/call with the operation name as the tool, the platform's agent profile URL in params.arguments.meta["ucp-agent"].profile, the UCP payload in structuredContent, and outputSchema pointing at the UCP JSON Schemas. So distributing a UCP server is distributing an MCP server.
// GET https://catalog.shopify.com/.well-known/ucp (abridged)
{
"ucp": {
"version": "2026-08-25",
"services": {
"dev.ucp.shopping": [{
"version": "2026-08-25",
"transport": "mcp",
"endpoint": "https://catalog.shopify.com/api/ucp/mcp",
"schema": "https://ucp.dev/2026-08-25/services/shopping/mcp.openrpc.json"
}]
},
"capabilities": { "dev.ucp.shopping.catalog.search": [ ... ], ... }
}
}Shopify's Global Catalog profile declares the endpoint used below, and Shopify's own quickstart installs its servers with a separate command per AI tool (Claude Code, Codex, Antigravity CLI, Cursor, VS Code). You are about to replace that matrix with one declaration.
| You need | Why |
|---|---|
| Node.js 18 or newer | agent-connector and the bin run on Node. |
| At least one agent host installed | Claude Code, Codex, Cursor, Gemini CLI, Windsurf, Zed or any other host with an adapter; detect lists what it finds. |
Network access to catalog.shopify.com | The endpoint answers initialize and tools/list without authentication. |
1. Create the package#
A connector is an npm package with agent-connector as a dependency. The package name, mcpName, bin and version are the connector's identity, so you never repeat them in the config.
mkdir shop-catalog-mcp && cd shop-catalog-mcp
npm init -y >/dev/null
npm install @ken-jo/agent-connector
# now replace package.json with the one below and add the two files{
"name": "@acme/shop-catalog-mcp",
"version": "0.1.0",
"description": "Shopify Global Catalog UCP MCP, installable into every agent host",
"type": "module",
"mcpName": "io.github.acme/shop-catalog",
"bin": { "shop-catalog": "./bin.mjs" },
"files": ["bin.mjs", "agent-connector.config.mjs"],
"dependencies": { "@ken-jo/agent-connector": "^0.6.4" }
}2. Declare the UCP endpoint#
Remote servers use transport: "http" and the endpoint from the business profile. The PreToolUse hook returns decision: "ask" for the checkout tools, so every host that supports hooks pauses before a purchase is created or completed.
import { defineConnector } from "@ken-jo/agent-connector/sdk";
// Shopify's Global Catalog is a UCP-compliant MCP server: a remote JSON-RPC
// endpoint declared in https://catalog.shopify.com/.well-known/ucp
export default defineConnector({
server: {
transport: "http",
url: "https://catalog.shopify.com/api/ucp/mcp",
tools: { include: ["*"] },
timeoutMs: 30_000,
},
hooks: {
// UCP checkout tools move money; every host that has hooks asks first.
PreToolUse: {
matcher: "create_checkout|update_checkout|complete_checkout",
async handler(evt) {
return { decision: "ask", reason: `Confirm ${evt.toolName} with the buyer` };
},
},
},
targets: "auto",
});Authenticated capabilities
Shopify's buyer-linked scopes and other authenticated UCP capabilities take a bearer token. Declare it once asauth: { type: "bearerEnv", bearerEnvVar: "SHOP_TOKEN" } in server; each host's config then references the environment variable in its own syntax. Field reference: Server.3. Add the bin and audit#
createConnectorCli() exposes every agent-connector subcommand under your bin, scoped to the connector beside it. audit checks that package.json, bin and connector agree before anything touches a host.
#!/usr/bin/env node
// bin.mjs — every agent-connector subcommand under your own bin, scoped to this connector
import { createConnectorCli } from "@ken-jo/agent-connector/cli";
createConnectorCli({
packageJson: new URL("./package.json", import.meta.url),
connector: new URL("./agent-connector.config.mjs", import.meta.url),
})
.run()
.then((code) => { process.exitCode = code; });$ node bin.mjs audit
✓ package name: @acme/shop-catalog-mcp
✓ package version: 0.1.0
✓ branded bin: shop-catalog
✓ @ken-jo/agent-connector dependency: ^0.6.4
✓ package audit passed.4. Preview the install#
install --dry-run detects the hosts on your machine and prints the plan without writing. This is the output on a machine with six hosts on 2026-09-06; yours lists the hosts you have.
$ shop-catalog install --dry-run
shop-catalog v0.1.0
server http · https://catalog.shopify.com/api/ucp/mcp
hooks PreToolUse
telemetry on
→ 6 agent hosts detected:
! claude-code MCP server + 1 hook ~/.claude.json, ~/.claude/settings.json
! telemetry not captured for shop-catalog on claude-code — remote (http) transport; per-tool telemetry is stdio-only
! codex MCP server + 1 hook ~/.codex/config.toml, ~/.codex/hooks.json
! cursor MCP server + 1 hook ~/.cursor/mcp.json, ~/.cursor/hooks.json
! gemini-cli MCP server + 1 hook ~/.gemini/settings.json
! windsurf MCP server ~/.codeium/windsurf/mcp_config.json
! zed 1 change ~/.config/zed/settings.json
✓ Would install shop-catalog to 6 hosts · 10 files (dry-run — nothing written).Read the report, not just the summary. Windsurf and Zed have no hook surface, so they receive the MCP server only. The telemetry line says per-tool token telemetry is not captured, because agent-connector measures tokens by wrapping a stdio server and cannot sit in front of a hosted endpoint. Both are facts about the hosts and the transport, reported rather than hidden.
5. Install, verify, uninstall#
# write the configs for real (same plan as the dry run)
node bin.mjs install
# health-check every host that received the connector
node bin.mjs doctor
# the full inverse — removes everything install wrote
node bin.mjs uninstall --dry-run
node bin.mjs uninstallAfter install, open one host and list its MCP servers: the connector appears under the name from package.json. doctor checks each host's config; for a remote transport it reports that the live stdio probe is skipped, which is expected. uninstall removes exactly what install wrote.
6. Verify the UCP endpoint itself#
Because the binding is plain MCP, two JSON-RPC calls confirm the endpoint independently of any host. UCP puts the platform's agent profile URL in the arguments; Shopify's docs publish example profiles you can use for this check.
# initialize — a UCP MCP server answers like any MCP server
curl -s https://catalog.shopify.com/api/ucp/mcp -H 'content-type: application/json' -d '{
"jsonrpc":"2.0","id":1,"method":"initialize",
"params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"probe","version":"0"}}
}'
# → {"result":{"protocolVersion":"2025-06-18","serverInfo":{"name":"universal-ucp-mcp",...}}}
# tools/list — UCP puts the platform's agent profile in params.arguments.meta
curl -s https://catalog.shopify.com/api/ucp/mcp -H 'content-type: application/json' -d '{
"jsonrpc":"2.0","id":2,"method":"tools/list",
"params":{"arguments":{"meta":{"ucp-agent":{"profile":"https://shopify.dev/ucp/agent-profiles/2026-08-25/valid-with-capabilities.json"}}}}
}'
# → tools: search_catalog, lookup_catalog, ... (input/response conform to dev.ucp.shopping.catalog.*)What success looks like#
| Check | Expected result |
|---|---|
node bin.mjs audit | Four checks pass; the bin name is shop-catalog. |
node bin.mjs install --dry-run | Every installed host is listed with the files it would receive; nothing is written. |
node bin.mjs install then a host's MCP list | The connector shows up under the package-derived name in each host you have. |
| Ask the host to search the catalog | The host calls search_catalog; results carry the UCP metadata envelope with prices in minor units. |
node bin.mjs uninstall | The entries and hook registrations are gone; doctor reports nothing installed. |
What agent-connector does not do for UCP#
| Concern | Where it lives |
|---|---|
Business profile at /.well-known/ucp | Served from the business origin; the connector references its endpoint. |
| Payments (AP2), identity linking (OAuth), order webhooks | The UCP server and the platform. agent-connector installs the server; it does not sit in the request path. |
| REST, A2A and embedded transports | Agent hosts consume MCP; the other transports are for platforms integrating directly. |
Next: the general publisher flow, including plugin marketplaces and the standard MCP artifacts, is in Publish your MCP server.