Spec-compliant Universal Commerce Protocol (UCP) profile generator for Magento 2.
Generates /.well-known/ucp at protocol version 2026-04-08 with ECDSA P-256 signing keys, declared capabilities, and proper cache headers — the discovery layer AI agents fetch first when interacting with your store.
v0.1.x is the profile-only release line. It exposes a valid UCP profile to AI platforms. The actual REST endpoints for catalog, cart, checkout and order land in later versions. Enabling a capability here adds it to the advertised profile but does NOT implement the matching endpoint — leave capabilities disabled in production until the matching endpoint module is installed. The current pre-release is
0.1.1-beta; install it explicitly per Installation below.
- Serves a spec-compliant UCP profile at
https://yourstore.com/.well-known/ucp - Declares the
dev.ucp.shoppingREST service binding - Lets you toggle which capabilities to advertise: catalog, cart, checkout, order, identity_linking
- Generates ECDSA P-256 signing keys (JWK + PEM) via CLI
- Returns correct
Cache-Control: public, max-age=300headers - Returns
404 ucp_not_advertisedwhen the module is disabled — never a misleading empty profile
| Requirement | Version |
|---|---|
| Magento | 2.4.7+ |
| PHP | 8.2 or 8.3 or 8.4 |
| OpenSSL extension | enabled |
The current 0.1.x line is a beta — install with the explicit @beta stability qualifier:
composer require angeo/module-ucp:^0.1@beta
bin/magento module:enable Angeo_Ucp
bin/magento setup:upgrade
bin/magento setup:di:compile
bin/magento cache:flushThe @beta qualifier scopes the stability exception to this package only — your project's other dependencies stay locked to whatever minimum-stability you have configured.
Once the 0.1.x line goes stable (planned after a short field-test window) the installation command will simply be composer require angeo/module-ucp.
Note on
0.1.0: an early0.1.0tag was published before the composer.json was valid and beforemagento/module-storewas declared as a dependency.0.1.0is treated as yanked — start from0.1.1-betaor later.
bin/magento angeo:ucp:keys:generateThis generates an ECDSA P-256 keypair, saves the public JWK to config, and prints the private PEM to stdout exactly once. Copy the private PEM into app/etc/env.php:
'ucp' => [
'signing_keys' => [
'angeo-ucp-2026-abcd' => '<PEM contents>',
],
],Stores → Configuration → Angeo → UCP → General → Advertise UCP Profile: Yes.
curl -s https://yourstore.com/.well-known/ucp | python3 -m json.toolExpected output:
{
"ucp": {
"version": "2026-04-08",
"services": {
"dev.ucp.shopping": [
{
"version": "2026-04-08",
"spec": "https://ucp.dev/2026-04-08/specification/overview",
"transport": "rest",
"endpoint": "https://yourstore.com/rest/V1/ucp",
"schema": "https://ucp.dev/2026-04-08/services/shopping/rest.openapi.json"
}
]
},
"capabilities": {}
},
"signing_keys": [
{
"kid": "angeo-ucp-2026-abcd",
"kty": "EC",
"crv": "P-256",
"x": "...",
"y": "...",
"use": "sig",
"alg": "ES256"
}
]
}bin/magento angeo:ucp:validate --jsonPrints a green pass if the profile is well-formed; non-zero exit on validation failure (useful as a cron healthcheck).
| Path | Field | Purpose |
|---|---|---|
| General → Advertise UCP Profile | Yes/No | Master switch for /.well-known/ucp |
| Capabilities → Catalog | Yes/No | Advertise dev.ucp.shopping.catalog |
| Capabilities → Cart | Yes/No | Advertise dev.ucp.shopping.cart |
| Capabilities → Checkout | Yes/No | Advertise dev.ucp.shopping.checkout |
| Capabilities → Order | Yes/No | Advertise dev.ucp.shopping.order |
| Capabilities → Identity Linking | Yes/No | Advertise dev.ucp.common.identity_linking |
| Transport → REST Endpoint URL | URL | Override the default {baseUrl}/rest/V1/ucp |
| Keys → Public JWK | textarea | Populated by keys:generate |
All capability and transport settings are scoped to the store view — multi-store deployments can advertise different profiles per storefront.
Multi-store on a single domain:
/.well-known/ucpis a single path on the host, so Magento's StoreResolver picks one store view to render it. If multiple store views share a host, the bare host resolves to one of them (typically the default), and that store's profile is what AI agents see. To advertise different UCP profiles per store, give each store its own hostname.
| Command | Purpose |
|---|---|
bin/magento angeo:ucp:keys:generate [--force] |
Generate a new P-256 keypair; print private PEM once, save public JWK to config |
bin/magento angeo:ucp:validate [--json] |
Validate the generated profile structure; optionally print the JSON |
HTTP request: GET /.well-known/ucp
│
▼
Angeo\Ucp\Controller\Router (sortOrder=22, runs before CMS router)
│
▼
Angeo\Ucp\Controller\WellKnown\Ucp (HttpGetActionInterface)
│
▼
Angeo\Ucp\Model\ProfileGenerator ← Angeo\Ucp\Model\Config
│ │
│ └── reads core_config_data
▼
JSON response with:
- Content-Type: application/json
- Cache-Control: public, max-age=300
- X-UCP-Version: 2026-04-08
- Private keys are never stored in the database. The
keys:generatecommand prints them once to stdout. Operators are responsible for placing them inapp/etc/env.phpor a secrets manager. Config::getPublicSigningKeys()strips private JWK fields (d,p,q,dp,dq,qi) as defence-in-depth before serialization, in case private material ever ends up in config by mistake.- HTTPS-only by design. The UCP spec requires HTTPS for
/.well-known/ucp; this module's audit check refuses a non-HTTPS endpoint URL. - Cache headers comply with the spec (
public,max-age >= 60). The module sendsmax-age=300.
composer install
vendor/bin/phpunit --testsuite=unitThree test classes cover the critical paths:
ProfileGeneratorTest— protocol version, namespace correctness, JSON encoding, capability togglingJwkFormatterTest— RFC 7518 base64url coordinate encoding, 32-byte P-256 width, private-field rejectionConfigTest— store-base-url fallback, private-key sanitization
CI runs the matrix PHP 8.2 / 8.3 / 8.4 on every push.
| Version | Scope |
|---|---|
| 0.1.1-beta (current) | Profile generator, signing keys, admin UI, CLI, tests, CI |
| 0.2.0 | dev.ucp.shopping.catalog real endpoint (search + lookup) backed by Magento_Catalog |
| 0.3.0 | UCP-Agent header parsing, platform profile fetching, capability intersection |
| 0.4.0 | RFC 9421 HTTP Message Signatures for outgoing responses |
| 0.5.0 | Cart capability |
| 1.0.0 | Production-ready full UCP shopping vertical |
Roadmap will shift as the UCP specification evolves.
MIT License — see LICENSE
Maintained by Ievgenii Gryshkun · info@angeo.dev