Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 13 additions & 12 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# next version
# 1.4.0

- Show the UCP tools only to UCP agents instead of on every Store API MCP connection. 1.3.0 put them into the group Shopware reserves for its own discovery tools, so every client connecting to `/store-api/_mcp` saw the thirteen UCP tools next to Shopware's instruction that no tools are listed until a toolset is enabled -- and models followed that instruction, enabling toolsets for tools they already had. The tools now form their own `ucp` toolset, and `/ucp/mcp` selects it at connect time, so a UCP agent still finds them on its first tool listing while a plain `/store-api/_mcp` connection lists only Shopware's discovery tools. On Shopware versions before `6.7.15.0`, which cannot select a toolset at connect time, the tools stay listed on every connection as before.
- Show the UCP tools only to AI agents that connect through `/ucp/mcp`, instead of to every client of Shopware's own MCP server at `/store-api/_mcp`. 1.3.0 put them into the group Shopware reserves for its own discovery tools, so every client connecting to `/store-api/_mcp` saw the thirteen UCP tools next to Shopware's instruction that no tools are listed until a toolset is enabled -- and models followed that instruction, enabling toolsets for tools they already had. The tools now form their own `ucp` toolset, and `/ucp/mcp` selects it at connect time, so a UCP agent still finds them on its first tool listing while a plain `/store-api/_mcp` connection lists only Shopware's discovery tools. On Shopware versions before `6.7.15.0`, which cannot select a toolset at connect time, the tools stay listed on every connection as before.
- Link the UCP settings to their documentation. The Exposure sub-tab of the Agentic Commerce tab now carries a link below the capability and transport checkboxes that opens the UCP section of the user documentation in a new tab, in the language of the administration. Until now the tab explained each option only in a one-line tooltip and gave no way to read on.
- Let an extension register its own UCP OAuth scope. The supported scopes were a private class constant, so a plugin that adds a UCP capability of its own had no way to make its scope grantable: the token request threw `Unsupported OAuth scope`, and a consent flow that swallowed the error burned its one-time handle and told the buyer the authorization link had expired. Tag a scope provider with `swag_agentic_commerce.ucp.oauth_scope_provider` and its scope is advertised in `scopes_supported` on `/.well-known/oauth-authorization-server` and accepted in an authorization request. A request that omits the scope still gets only the three built-in ones; an extension scope has to be asked for by name. An unregistered scope is still rejected -- now with the supported set named in the message, which is what made this hard to diagnose.
- Keep the settings that other extensions add to the _General_ tab of a sales channel. The extension replaced the tab's content as a whole, so an extension that passes its own data to the tab lost it, and the tab showed the default settings of a storefront sales channel instead.
- Let an extension register its own UCP OAuth scope. The supported scopes were a private class constant, so a plugin that adds a UCP capability of its own had no way to make its scope grantable: the token request threw `Unsupported OAuth scope`, and a consent flow that swallowed the error had already used up its one-time link and told the buyer the link had expired. Tag a scope provider with `swag_agentic_commerce.ucp.oauth_scope_provider` and its scope is advertised in `scopes_supported` on `/.well-known/oauth-authorization-server` and accepted in an authorization request. A request that omits the scope still gets only the three built-in ones; an extension scope has to be asked for by name. An unregistered scope is still rejected -- now with the supported set named in the message, which is what made this hard to diagnose.
- Require Shopware `6.5.8` or newer. `6.5.0.0` through `6.5.7.4` were listed as compatible but could never install: those versions ship Symfony 6.3, while both the extension's own routes and the UCP SDK need Symfony 6.4. Installation therefore ended in a Composer error about `symfony/config` that a merchant cannot act on. Such a shop now sees the extension as incompatible; updating to `6.5.8.x` fixes that and stays inside the same minor.
- Let Shopware install the UCP SDK instead of shipping it inside the archive. 1.3.0 put the SDK in the plugin's own `vendor/` and loaded the autoloader Composer had generated for it, because Shopware does not load a plugin's `vendor/autoload.php` by itself. Every shop that installed it then carried two separate package registries: FroshTools reported `2 autoloaders registered`, and a question as ordinary as which version of a package is installed could be answered from the plugin's copy instead of the shop's. The extension now carries no dependencies at all. It has Shopware run `composer require` on install and update instead, which is what that mechanism is there for on a zip-installed extension: the extension itself resolves from the `custom/plugins/*` path repository every Shopware project declares, and the SDK version it names comes from Packagist into the shop's own `vendor/`. Nothing changes for a shop that installs through Composer. What is new is that installing has to reach Packagist -- without it the install stops with a Composer error, rather than leaving an extension that cannot run.
- Let Shopware install the UCP SDK instead of shipping it inside the archive. 1.3.0 put the SDK in the plugin's own `vendor/` and loaded the autoloader Composer had generated for it, because Shopware does not load a plugin's `vendor/autoload.php` by itself. Every shop that installed it then carried two separate package registries: FroshTools reported `2 autoloaders registered`, and a question as ordinary as which version of a package is installed could be answered from the plugin's copy instead of the shop's. The extension now carries no dependencies at all. It has Shopware run `composer require` on install and update instead, which is what that mechanism is there for on a zip-installed extension: the extension itself resolves from the `custom/plugins/*` path repository every Shopware project declares, and the SDK version it names comes from Packagist into the shop's own `vendor/`. Nothing changes for a shop that installs through Composer. What is new is that the shop needs to reach Packagist (`packagist.org`) while installing or updating the extension -- without it the install stops with a Composer error, rather than leaving an extension that cannot run.
- Switch the extension off instead of taking the shop down when the SDK is missing. An update extracts the new files one request before Shopware runs Composer, so an active extension boots at least once without the dependency it needs. On 1.3.0 every page answered `500` from that moment on, the storefront included, until someone installed the SDK by hand. The extension now registers no services, routes or feeds in that state, and writes to `var/log/swag-agentic-commerce.log` what is missing and the command that fixes it. Once the SDK is there it picks up again on its own. The check asks not only whether an SDK is present but whether it is the version this release names, so a shop still holding the previous one waits instead of running new code against an old SDK. The README has a _Troubleshooting_ section covering what that state looks like, how to leave it, and what to expect when updating from 1.3.0 or older. A cluster setup is the exception: Shopware never runs Composer for a plugin there, so nothing would ever install the requirements, and the extension refuses the install rather than reporting success and then doing nothing.
- Keep the settings that other extensions add to the _General_ tab of a sales channel. The extension replaced the tab's content as a whole, so an extension that passes its own data to the tab lost it, and the tab showed the default settings of a storefront sales channel instead.

# 1.3.0

Expand All @@ -17,15 +17,16 @@
- Answer a UCP request for a cart nobody created with `not_found` instead of handing out a fresh empty cart under the guessed id. Cart ids handed out by `cart.create` are remembered in the same context store the checkout session already uses.
- Name the UCP MCP tools as the specification's OpenRPC document does (`search_catalog`, `create_cart`, `create_checkout`, `complete_checkout`, `get_order` and so on) and advertise them on a fresh MCP session. They were named `shopware-ucp-*` and hidden behind a toolset an agent had to enable first, so a spec-following agent listing tools on `/ucp/mcp` saw only the toolset meta-tools. An MCP client that called the old names has to switch; the arguments are unchanged.
- Return real product descriptions from catalog search and lookup, with the product title as the fallback for a product that has none.
- Apply checkout completion payment data through the platform gateway and expose the applied-discount breakdown.
- Enforce configured profile-fetch allowlists and prevent checkout tokens from leaking through embedded responses.
- Completing an agentic checkout keeps working on upcoming Shopware versions: the guest customer created during completion rotates the Shopware context token and moves the cart with it, and the order is now placed against the new token instead of the stale one, which newer Shopware versions reject with a "cart not found" error.
- Hand the payment an agent sends with `checkout.complete` to an extension point that a payment extension can implement. By default nothing changes for the order: it is still charged with the sales channel's default payment method, and the shop log now warns which payment method the agent asked for.
- List the discounts applied to a cart one by one under `discounts.applied`, with code, name and amount, instead of only a total.
- Load agent profiles only from the hosts on the configured allowlist, and keep the secret address of the embedded checkout page from reaching other websites when the buyer clicks through from it.
- Completing an agentic checkout keeps working on upcoming Shopware versions. Creating the guest customer during completion gives the buyer a new Shopware session, and the order is now placed in that new session instead of the old one, which newer Shopware versions reject with a "cart not found" error.
- Product links in the OpenAI and Google product feeds now resolve correctly for headless sales channels on Shopware 6.7.14 and newer, so agents receive working product URLs; the feeds keep working unchanged on earlier Shopware versions.
- Restrict UCP to the sales channels that can actually complete a purchase: Storefront and Headless. Product feed channels are no longer offered for UCP and can no longer have it switched on through the API or the console; one that had it switched on before is now treated as switched off, so no shop is advertised that an agent cannot buy from.
- Serve `/.well-known/api-catalog` (RFC 9727 linkset) on exposed sales channels, so an agent can discover the shop's UCP profile and Store API entry point from one standardised location; unexposed channels return 404.
- Serve `/.well-known/api-catalog` (RFC 9727 linkset) on sales channels exposed to UCP, so an agent can discover the shop's UCP profile and Store API entry point from one standardised location; other channels return `404`.
- Add `ucp:setup`, which configures a sales channel for UCP in one step: exposure, security defaults, a signing key when the channel has none, the readiness checks and the first request to run. `--dev` picks local defaults so the shop can act as its own agent; without it the defaults are production ones. The README now walks through the whole setup in four steps.
- Count which UCP versions agents actually speak: one `info` record per request on the new `ucp_negotiation` log channel with the agent's declared version, the served version, the outcome and the agent profile host, nothing else. This is the measurement the single-version policy is revisited on, and SDK `0.0.7` reports it.
- Serve UCP `2026-08-25` through SDK `0.0.7`, including version-aware capability negotiation, the standard catalog capability IDs and updated consent, fulfillment and payment shapes.
- Count which UCP versions agents actually speak: one `info` record per request on the new `ucp_negotiation` log channel with the agent's declared version, the served version, the outcome and the agent profile host, nothing else. These numbers decide whether the plugin should one day serve more than one UCP version at a time; SDK `0.0.7` reports them.
- Serve version `2026-08-25` of the UCP specification through SDK `0.0.7`, including version-aware capability negotiation, the standard catalog capability IDs and updated consent, fulfillment and payment shapes.
- Require the exact UCP SDK version the release was tested against (`0.0.7`) and stop configuring `ucp_sdk.version`. The SDK serves one UCP version per release and defaults to it, so an SDK release now arrives together with a plugin release instead of reaching shops on its own, and the plugin can no longer name a version its linked SDK does not serve. Version 1.2.x combined a pinned `2026-04-08` with a `>=0.0.5 <0.1.0` window: `composer update` resolved SDK 0.0.6, which no longer served that version, and the container build failed inside `assets:install` part-way through a Shopware core upgrade. `docs/ucp-version-support.md` explains what the plugin serves and what a spec bump means for a shop.
- Store the administration translations in country-agnostic files (`de.json`, `en.json`) following the current Shopware core convention; a compatibility loader keeps them working on Shopware versions before 6.7.3.
- Polish the administration texts: consistent capitalisation of the informal German address and a clearer "Total" label in the English statistics summary.
Expand All @@ -37,7 +38,7 @@
- Read the shipping address from where UCP sends it, so a checkout with separate shipping and billing addresses no longer ships to the billing one.
- Always send an absolute, openable order link in `order.permalink_url` -- for guests it is the order's deep link, which works without logging in, and it is the same link the confirmation email uses.
- Refuse a guest order read in the protocol's own vocabulary: an agent asking for someone else's guest order is told the order was not found and that the permalink is how a guest order is read, rather than receiving an internal error.
- Add a dry-run mode and actionable error messages to the UCP MCP tools, so an agent that gets a request wrong is told which field and why instead of receiving an opaque failure.
- Let an agent test a request to the UCP MCP tools before carrying it out: with `dryRun` the request is only checked and nothing is saved. A request that fails now says which field is wrong and why, instead of returning an opaque error.
- Report the code and severity of a failed agent request, and log the underlying exception, so a failure can be diagnosed from the shop's log.
- Show the Agentic Commerce tab only on sales channels that can actually sell, and fix tab, template-selection and save-button inconsistencies across Shopware 6.5, 6.6 and 6.7.
- Mark a product that has variants correctly in the OpenAI feed. `listing_has_variations` was set only when the export had variants switched on, and the variant fields were written for the parent listing as well; the flag now follows the product itself and `variant_dict` appears only on an actual variant.
Expand Down
Loading
Loading