{"id":49326818,"url":"https://github.com/runtypelabs/ucp-example-server","last_synced_at":"2026-04-26T20:32:27.134Z","repository":{"id":351441117,"uuid":"1210126638","full_name":"runtypelabs/ucp-example-server","owner":"runtypelabs","description":"Easily test your UCP clients and agents with this example server","archived":false,"fork":false,"pushed_at":"2026-04-15T01:59:57.000Z","size":92,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-15T03:23:41.765Z","etag":null,"topics":["example","server","ucp"],"latest_commit_sha":null,"homepage":"https://ucp.runtype.dev","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/runtypelabs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-14T05:39:53.000Z","updated_at":"2026-04-15T02:00:02.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/runtypelabs/ucp-example-server","commit_stats":null,"previous_names":["runtypelabs/ucp-example-server"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/runtypelabs/ucp-example-server","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/runtypelabs%2Fucp-example-server","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/runtypelabs%2Fucp-example-server/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/runtypelabs%2Fucp-example-server/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/runtypelabs%2Fucp-example-server/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/runtypelabs","download_url":"https://codeload.github.com/runtypelabs/ucp-example-server/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/runtypelabs%2Fucp-example-server/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32312306,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-26T19:15:34.056Z","status":"ssl_error","status_checked_at":"2026-04-26T19:15:15.467Z","response_time":129,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["example","server","ucp"],"created_at":"2026-04-26T20:32:26.657Z","updated_at":"2026-04-26T20:32:27.125Z","avatar_url":"https://github.com/runtypelabs.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# UCP Example Store Server\n\nA reference implementation of a UCP Merchant Server running as a **Python Worker\non Cloudflare**, using **FastAPI** and **Cloudflare D1** (serverless SQLite).\n\nImplements the UCP **v2026-04-08** specification including the new Catalog Search\nand Catalog Lookup capabilities for product discovery.\n\n**Live demo** (reference deployment): https://ucp.runtype.dev\n\n## Capabilities\n\n| Capability | Endpoints |\n|-----------|-----------|\n| Catalog Search | `POST /catalog/search` |\n| Catalog Lookup | `POST /catalog/lookup`, `POST /catalog/product` |\n| Checkout | `POST /checkout-sessions`, `GET/PUT /checkout-sessions/{id}` |\n| Checkout Complete | `POST /checkout-sessions/{id}/complete` |\n| Discount | Applied via `PUT /checkout-sessions/{id}` |\n| Fulfillment | Applied via `PUT /checkout-sessions/{id}` |\n| Order | `GET /orders/{id}`, `PUT /orders/{id}` |\n| Cart | `POST /carts`, `GET/PUT /carts/{id}`, `POST /carts/{id}/cancel` |\n| Discovery | `GET /.well-known/ucp` |\n\n## Prerequisites\n\n1. Install [uv](https://docs.astral.sh/uv/): `curl -LsSf https://astral.sh/uv/install.sh | sh`\n2. Install [Node.js](https://nodejs.org/) (for wrangler)\n3. A Cloudflare account (free tier works)\n\n## Local Development\n\n```bash\ncd ucp-cloudflare-workers\n\n# Install dependencies (includes workers-py, workers-runtime-sdk, pytest)\nuv venv \u0026\u0026 uv sync --all-groups\n\n# Create and seed the local D1 database\nnpx wrangler d1 execute ucp-flower-shop --local --file=migrations/0001_schema.sql\nnpx wrangler d1 execute ucp-flower-shop --local --file=migrations/0002_seed.sql\nnpx wrangler d1 execute ucp-flower-shop --local --file=migrations/0003_catalog.sql\nnpx wrangler d1 execute ucp-flower-shop --local --file=migrations/0004_carts.sql\nnpx wrangler d1 execute ucp-flower-shop --local --file=migrations/0005_product_options.sql\n\n# Start the dev server\nuv run pywrangler dev --port 8787\n```\n\n## Test\n\n```bash\n# Discovery\ncurl http://localhost:8787/.well-known/ucp | python3 -m json.tool\n\n# Search catalog\ncurl -X POST http://localhost:8787/catalog/search \\\n  -H \"Content-Type: application/json\" \\\n  -H 'UCP-Agent: profile=\"https://agent.example/profile\"' \\\n  -H \"request-signature: test\" \\\n  -H \"request-id: test-1\" \\\n  -d '{\"query\": \"roses\"}'\n\n# Create checkout\ncurl -X POST http://localhost:8787/checkout-sessions \\\n  -H \"Content-Type: application/json\" \\\n  -H 'UCP-Agent: profile=\"https://agent.example/profile\"' \\\n  -H \"request-signature: test\" \\\n  -H \"idempotency-key: test-key\" \\\n  -H \"request-id: test-2\" \\\n  -d '{\n    \"line_items\": [{\"item\": {\"id\": \"bouquet_roses\", \"title\": \"Roses\"}, \"quantity\": 1}],\n    \"buyer\": {\"full_name\": \"Jane Doe\", \"email\": \"jane@example.com\"},\n    \"currency\": \"USD\",\n    \"payment\": {\"instruments\": [], \"handlers\": []}\n  }'\n```\n\n## Unit tests\n\n```bash\nuv run pytest\n```\n\n## Deploy\n\n```bash\n# Login to Cloudflare\nnpx wrangler login\n\n# Set your account ID in wrangler.toml or env\nexport CLOUDFLARE_ACCOUNT_ID=\"your-account-id\"\n\n# Create the D1 database\nnpx wrangler d1 create ucp-flower-shop\n# Update database_id in wrangler.toml with the returned ID\n\n# Apply migrations to remote\nnpx wrangler d1 execute ucp-flower-shop --remote --file=migrations/0001_schema.sql\nnpx wrangler d1 execute ucp-flower-shop --remote --file=migrations/0002_seed.sql\nnpx wrangler d1 execute ucp-flower-shop --remote --file=migrations/0003_catalog.sql\nnpx wrangler d1 execute ucp-flower-shop --remote --file=migrations/0004_carts.sql\nnpx wrangler d1 execute ucp-flower-shop --remote --file=migrations/0005_product_options.sql\n\n# Deploy\nuv run pywrangler deploy\n```\n\n## Architecture\n\n```\nCloudflare Workers (Pyodide / Python 3.12)\n├── FastAPI (ASGI adapter built into Workers runtime)\n├── Pydantic models (inline, no ucp-sdk dependency)\n├── httpx (async, for webhook notifications)\n└── D1 Database (serverless SQLite)\n    ├── products, promotions, inventory\n    ├── checkouts, orders\n    └── customers, discounts, shipping_rates\n```\n\nKey design decisions:\n\n- **Eager module-level imports** — FastAPI, routes, and `asgi` are imported at module scope so the Workers runtime captures them in the [deploy-time memory snapshot](https://developers.cloudflare.com/workers/languages/python/how-python-workers-work/#deployment-lifecycle-and-cold-start-optimizations). Cold starts boot from the snapshot and skip import work.\n- **`python_dedicated_snapshot` compatibility flag** — opts into per-Worker dedicated snapshotting (the actual cold-start optimization).\n- **No `uuid.uuid4()` at module level** — Workers restricts `os.urandom()` outside request context, so any randomness must happen inside `on_fetch`.\n\n## Project Structure\n\n```\nsrc/\n  entry.py              — Workers fetch handler → ASGI adapter\n  app.py                — FastAPI app, exception handlers, router registration\n  db.py                 — D1 database layer (all SQL queries)\n  models.py             — Pydantic models for UCP schemas\n  exceptions.py         — UCP error hierarchy\n  enums.py              — Checkout/order status enums\n  routes/\n    catalog.py          — POST /catalog/search, /catalog/lookup, /catalog/product\n    cart.py             — Cart CRUD + cancel\n    checkout.py         — Checkout CRUD + order + webhook endpoints\n    discovery.py        — GET /.well-known/ucp\n    home.py             — GET / (interactive HTML page)\n    platform.py         — Optional platform session/log helpers\n  services/\n    cart_service.py     — Cart persistence and validation\n    checkout_service.py — Checkout lifecycle, payments, inventory, totals\n    fulfillment_service.py — Shipping option calculation\nmigrations/\n  0001_schema.sql       — D1 table definitions\n  0002_seed.sql         — Flower shop seed data\n  0003_catalog.sql      — Catalog fields (description, handle, categories)\n  0004_carts.sql        — Cart tables\n  0005_product_options.sql — Product options columns\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fruntypelabs%2Fucp-example-server","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fruntypelabs%2Fucp-example-server","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fruntypelabs%2Fucp-example-server/lists"}