{"_id":"@agentkitai/agentgate-ucp","_rev":"3-cd1d46573536946f8e85624c878531b2","name":"@agentkitai/agentgate-ucp","dist-tags":{"latest":"0.1.1"},"versions":{"0.1.0":{"name":"@agentkitai/agentgate-ucp","version":"0.1.0","keywords":["ucp","agentgate","mcp","commerce","approval","unattended-agents"],"license":"MIT","_id":"@agentkitai/agentgate-ucp@0.1.0","maintainers":[{"name":"amit-paz","email":"amit.paz@gmail.com"}],"homepage":"https://agentkitai.github.io/agentgate-ucp/","bugs":{"url":"https://github.com/agentkitai/agentgate-ucp/issues"},"bin":{"agentgate-ucp":"dist/index.js"},"dist":{"shasum":"d8b31f2366ddecea9b2920580ea398a780e555e2","tarball":"https://registry.npmjs.org/@agentkitai/agentgate-ucp/-/agentgate-ucp-0.1.0.tgz","fileCount":116,"integrity":"sha512-DvDn8dkxXx8NJT6O2O+Wnr7Ja6PsLWK/BtgahoWbg9MPpdpIk7Om8MUN1cL8nIf4Zs42sS+ATKhdpde5c4AQCw==","signatures":[{"sig":"MEQCIAJz9d68A5bKxC8Xa7FP3ECa9L9p9Lg210YmlY3yCUXiAiA9uM8o4iVte2znVuJRE8ofcugQ+ziasN8z6mgwegOLUA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":313355},"main":"./dist/index.js","type":"module","engines":{"node":">=20"},"gitHead":"90498b91697ac8adaa8e2f8ab535807bc2df3ed6","scripts":{"dev":"tsx watch src/index.ts","test":"vitest","build":"tsc -p tsconfig.build.json && node scripts/copy-schemas.mjs","start":"node dist/index.js","test:run":"vitest run","typecheck":"tsc --noEmit","prepublishOnly":"npm run build"},"_npmUser":{"name":"amit-paz","email":"amit.paz@gmail.com"},"repository":{"url":"git+https://github.com/agentkitai/agentgate-ucp.git","type":"git"},"_npmVersion":"11.5.2","description":"The approval gate for unattended UCP buying agents — a policy/approval MCP proxy in front of a merchant's UCP checkout endpoint.","directories":{},"_nodeVersion":"24.12.0","dependencies":{"zod":"^3.25.76","hono":"^4.12.25","jsonpath-plus":"^10.4.0","better-sqlite3":"^11.6.0","@hono/node-server":"^1.19.10","json-schema-merge-allof":"^0.8.1","@agentkitai/agentgate-sdk":"^0.1.0","@modelcontextprotocol/sdk":"^1.26.0","@apidevtools/json-schema-ref-parser":"^15.4.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.19.2","vitest":"^3.2.6","typescript":"^5.7.3","@types/node":"^22.10.0","@types/better-sqlite3":"^7.6.11"},"_npmOperationalInternal":{"tmp":"tmp/agentgate-ucp_0.1.0_1783251896026_0.2181581686260574","host":"s3://npm-registry-packages-npm-production"},"deprecated":"Security: 0.1.0 predates the red-team security audit (webhook fail-open, unauthenticated /mcp, forgeable evidence). Use >=0.1.1."},"0.1.1":{"name":"@agentkitai/agentgate-ucp","version":"0.1.1","keywords":["ucp","agentgate","mcp","commerce","approval","unattended-agents"],"license":"MIT","_id":"@agentkitai/agentgate-ucp@0.1.1","maintainers":[{"name":"amit-paz","email":"amit.paz@gmail.com"}],"homepage":"https://agentkitai.github.io/agentgate-ucp/","bugs":{"url":"https://github.com/agentkitai/agentgate-ucp/issues"},"bin":{"agentgate-ucp":"dist/index.js"},"dist":{"shasum":"a65fa9db9af9d647874621e37c68ae50b81e233c","tarball":"https://registry.npmjs.org/@agentkitai/agentgate-ucp/-/agentgate-ucp-0.1.1.tgz","fileCount":116,"integrity":"sha512-MRU3o+8syCGeUA7IbjYWLVgpxm9Ye/hxO09m0OmK3TFE7BA9eeUzU/hEkelWkCemK+Q9+jim59hgWds8V8WvxQ==","signatures":[{"sig":"MEQCIFZhH6VOhQg85WOk+A2/ChyTVw9XTdNjp805JLn5+ovWAiAdLPyIB7OUh8Mqa0l3QEkFm/tnF/RYfoJMAWWQX7w0KQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@agentkitai%2fagentgate-ucp@0.1.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":324186},"main":"./dist/index.js","type":"module","engines":{"node":">=20"},"gitHead":"7cad9d0fe0f5a9f62855017c2694c1c9e83ed5ae","scripts":{"dev":"tsx watch src/index.ts","test":"vitest","build":"tsc -p tsconfig.build.json && node scripts/copy-schemas.mjs","start":"node dist/index.js","test:run":"vitest run","typecheck":"tsc --noEmit","prepublishOnly":"npm run build"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:1600e2c9-d746-4e64-b203-b9d8142718ef"}},"repository":{"url":"git+https://github.com/agentkitai/agentgate-ucp.git","type":"git"},"_npmVersion":"11.18.0","description":"The approval gate for unattended UCP buying agents — a policy/approval MCP proxy in front of a merchant's UCP checkout endpoint.","directories":{},"_nodeVersion":"22.23.1","dependencies":{"zod":"^4.4.3","hono":"^4.12.25","jsonpath-plus":"^10.4.0","better-sqlite3":"^12.11.1","@hono/node-server":"^2.0.8","json-schema-merge-allof":"^0.8.1","@agentkitai/agentgate-sdk":"^0.1.0","@modelcontextprotocol/sdk":"^1.26.0","@apidevtools/json-schema-ref-parser":"^15.4.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.19.2","vitest":"^4.1.9","typescript":"^6.0.3","@types/node":"^26.1.0","@types/better-sqlite3":"^7.6.11"},"_npmOperationalInternal":{"tmp":"tmp/agentgate-ucp_0.1.1_1783522139483_0.3931324866306849","host":"s3://npm-registry-packages-npm-production"}}},"time":{"created":"2026-07-05T11:44:55.868Z","modified":"2026-07-09T05:50:36.203Z","0.1.0":"2026-07-05T11:44:56.175Z","0.1.1":"2026-07-08T14:48:59.673Z"},"bugs":{"url":"https://github.com/agentkitai/agentgate-ucp/issues"},"license":"MIT","homepage":"https://agentkitai.github.io/agentgate-ucp/","keywords":["ucp","agentgate","mcp","commerce","approval","unattended-agents"],"repository":{"url":"git+https://github.com/agentkitai/agentgate-ucp.git","type":"git"},"description":"The approval gate for unattended UCP buying agents — a policy/approval MCP proxy in front of a merchant's UCP checkout endpoint.","maintainers":[{"name":"amit-paz","email":"amit.paz@gmail.com"}],"readme":"# @agentkitai/agentgate-ucp\n\n**The approval gate for unattended UCP buying agents.**\n\n[![npm](https://img.shields.io/npm/v/@agentkitai/agentgate-ucp?logo=npm&color=cb3837)](https://www.npmjs.com/package/@agentkitai/agentgate-ucp) &nbsp; [![license: MIT](https://img.shields.io/badge/license-MIT-2f6f66.svg)](LICENSE)\n\n![A gated purchase, animated — an unattended agent places an order, the gate parks it over budget, a human approves at their computer, and it completes with a verifiable evidence trail.](docs/agentgate-ucp-demo.gif)\n\n**▶ [Play the interactive walkthrough](https://agentkitai.github.io/agentgate-ucp/flow.html)** &nbsp;·&nbsp; [read the launch post](https://agentkitai.github.io/agentgate-ucp/)\n\nA thin MCP server (\"the gate\") that a buying agent connects to *instead of* a\nmerchant's [UCP](https://github.com/universal-commerce-protocol) checkout\nendpoint. It re-exposes the UCP checkout tools 1:1 and passes everything through\n— except it runs a **policy / approval / evidence** layer before money moves.\n\n> UCP's escalation model assumes a human is present at the surface. For\n> **unattended** agents — scheduled replenishment, procurement, background jobs —\n> nobody is watching. This is the missing approval layer, plus a tamper-evident\n> record of every gated purchase.\n\nThe agent still speaks plain UCP. It never learns there's a gate in front of the\nmerchant; it just sometimes gets an escalation back (with a link a human\nresolves) instead of a completed order.\n\n## Run\n\n```bash\nnpx @agentkitai/agentgate-ucp        # run the gate (or: npm i -g @agentkitai/agentgate-ucp)\n```\n\nConfigure via environment (see [`.env.example`](.env.example)) — required:\n`MCP_AUTH_TOKEN` (the bearer token agents present on `/mcp`), `MERCHANT_URL`,\n`AGENTGATE_URL`, `AGENTGATE_API_KEY`, and `AGENTGATE_WEBHOOK_SECRET` (the decision\nwebhook moves money, so it must be signed). FormBridge and AgentLens are optional\n(unset each and that seam passes through). Then point your agent's MCP client at\n`$PUBLIC_URL/mcp` (default `http://localhost:8787/mcp`) with\n`Authorization: Bearer $MCP_AUTH_TOKEN`.\n\n## What it does — three gate points\n\nThe five checkout tools (`create` / `get` / `update` / `complete` / `cancel_checkout`)\npass straight through to the merchant. Three seams add control:\n\n**① Spend policy** — on `complete_checkout`, the gate fetches the merchant's\n**authoritative** totals (never the agent-supplied amount), evaluates them\nagainst [AgentGate](https://github.com/agentkitai/agentgate) spend policy, and\neither forwards, denies, or **parks** the completion. A parked purchase waits\nfor a human's approval (Slack / dashboard) and is replayed out-of-band — with\nthe **original idempotency key** — the moment they approve.\n\n**② Merchant escalations** — when the merchant itself answers a completion with\na `requires_escalation` (an inventory hold, a fraud review), the gate surfaces\nit **faithfully** to the agent — never misreporting a held order as placed.\n\n**③ Buyer-input form handoff** — when the merchant needs a field only a human\ncan supply (`requires_buyer_input`), the gate resolves the **real UCP field\nschema** at that JSONPath, builds a **typed** [FormBridge](https://github.com/agentkitai/formbridge)\nform, and hands back a resume link. The human fills it; the gate writes the\nanswer back to its exact path, `update_checkout`s, and re-drives completion\n**through the spend gate again**.\n\n## Evidence — every gated purchase is provable\n\nThe gate self-emits a hash-chained timeline of each purchase into\n[AgentLens](https://github.com/agentkitai/agentlens), keyed one session per\ncheckout (`received → decision → parked → approved/replayed → placed`).\n\n- **Tier A** works with any AgentLens: `GET /api/audit/verify?sessionId=ucp_<checkout>`\n  proves the chain is intact (`verified:true, brokenChains:[]`).\n- **Tier B** (AgentLens configured with a signing key + agent-token verification):\n  a **signed, portable, offline-verifiable** `agentlens.evidence-pack/v1` keyed on\n  a server-derived `verified_agent_id` — dispute-grade proof that *this agent*\n  made *this purchase*, checkable without the database.\n\n## Architecture\n\n```\nBuying agent ──MCP──▶  agentgate-ucp  ──REST──▶  Merchant UCP checkout\n                          │   ▲   │\n            spend policy  │   │   └───emit───▶  AgentLens   (hash-chained evidence)\n                          ▼   │\n                     AgentGate  ──▶ Slack / dashboard   (human approves)\n                          │\n                    decision webhook (HMAC) ──▶ gate replays the parked completion\n\n   requires_buyer_input ──▶ FormBridge (typed form) ──▶ human ──▶ answer-back\n                            webhook (HMAC) ──▶ gate writes answer, re-drives complete\n```\n\n## Try it — the live demo\n\n`demo/run-demo.sh` stands up all five services locally and drives four scenarios\nend to end, capturing a transcript:\n\n| | Scenario | Proves |\n|---|---|---|\n| A | over-spend | parked → human approves in AgentGate → decision webhook → replayed → completed |\n| B | under-spend | auto-approved, completes immediately |\n| C | merchant hold | a merchant `requires_escalation` surfaced faithfully (no order placed) |\n| D | buyer-input | typed FormBridge form → human fills → answer-back → re-drive → completed, with a verified AgentLens chain |\n\n```bash\nbash demo/run-demo.sh   # merchant :3100, agentgate :4000, formbridge :8091, gate :8787\n```\n\nSee [`demo/README.md`](demo/README.md) for the topology and the recorded\n[`demo/transcript.txt`](demo/transcript.txt).\n\n## Security posture\n\n- **Authenticated endpoint.** `/mcp` requires a bearer `MCP_AUTH_TOKEN` — an\n  unauthenticated request never reaches the merchant. The gate refuses to start\n  without the token.\n- **Authoritative amounts, fail-closed.** The spend gate reads totals from the\n  merchant, never from the agent-supplied object; a checkout with no valid grand\n  total is *refused*, not gated as $0. The approved total is re-checked immediately\n  before the charge (an ungated `update_checkout` can't slip a pricier cart past the\n  gate), and a buyer's form answer that changes the total is re-gated on the re-drive.\n- **Fail-closed webhooks (both).** The AgentGate *and* FormBridge webhooks are\n  HMAC-verified over the raw body, are *only registered when their secret is set*,\n  and the gate refuses to start without them — no unsigned decision or answer-back\n  can move money.\n- **At-least-once + tamper safe.** Parked completions replay the stored snapshot\n  with the pinned idempotency key, not the webhook's params, and are resumed via an\n  *atomic claim* (with a crash-recovery lease) so a duplicate delivery can't\n  double-place and a mid-replay crash can't strand a human-approved order.\n- **Hardened JSONPath.** Buyer-input answers write to exactly one concrete\n  location; `__proto__`/`constructor`/`prototype` and wildcard/filter/negative-index\n  paths are rejected (no prototype pollution, no fan-out).\n- **Crash-recoverable.** Parked forms use a lease so a mid-flight crash can never\n  strand an answered order.\n\nHardened by two independent adversarial reviews (a multi-lens workflow + Codex\ngpt-5.5) — 30+ findings fixed before release, each with a regression test.\n\n## Develop\n\n```bash\nnpm install\ncp .env.example .env     # MCP_AUTH_TOKEN / MERCHANT_URL / AGENTGATE_URL / AGENTGATE_API_KEY / AGENTGATE_WEBHOOK_SECRET required\nnpm run dev              # gate on :8787, MCP at /mcp\nnpm run typecheck\nnpm test                 # 151 tests\nnpm run build && node dist/index.js\n```\n\nLocal topology: merchant `:3100`, AgentGate `:4000`, FormBridge `:8091`,\nAgentLens `:3000`, gate `:8787`. Every integration (AgentGate aside) is optional\n— unset its URL and that seam passes through untouched.\n\n## Status\n\nGate points 1–3 + evidence complete and demo-verified end to end. Targets the\nmerged UCP checkout surface (`requires_escalation` + `messages[]` + `continue_url`);\ntracking the in-flight Actions primitive ([UCP #553](https://github.com/universal-commerce-protocol)).\n\nMIT.\n","readmeFilename":"README.md"}