Repository navigation
Releases: tpaksu/woocommerce-agent-tools
Release list
0.5.1
A look at the Tools screen, and configuration for more clients. The confirmation gate and the derived surface are unchanged from 0.5.0.
This is a prototype for internal evaluation. It works, it is linted, and the confirmation gate's token lifecycle has unit tests. The rest is not hardened and has no tests of its own.
Install
Needs WooCommerce and the MCP Adapter active first; the plugin header declares both. Upload the zip, activate, then go to Tools, Agent Tools.
Changed
- Rework the Tools screen. It leads with what the store exposes, how much of that changes something, and how much comes back to the merchant; the two stages of setup are numbered panels rather than three equal headings; the clients collapse so you read one; and the warning about what the agent inherits sits above the button that issues the credential rather than below it, which is where the decision it describes is made.
- The Tools screen hands you ready-made configuration for Claude Desktop, Cursor and VS Code as well as Claude Code, each with the file it belongs in. Every client but one was previously left to work out the transport and headers for itself.
- The gate told the agent to put the preview in front of the merchant "in those terms", which meant reading them the tool name and the raw field names. It now asks for the same substance in the merchant's own words, and the preview renders
discount_type=percentasdiscount type: percentso a verbatim relay is not code either.
Full history is in changelog.txt.
0.5.0
Compiles the REST routes of WooCommerce and the extensions beside it into MCP abilities, so a connected agent sees what the store can actually do. Every write is held until it has been stated.
This is a prototype for internal evaluation. It works, it is linted, and the confirmation gate's token lifecycle has unit tests. The rest is not hardened and has no tests of its own.
Install
Needs WooCommerce and the MCP Adapter active first; the plugin header declares both, so WordPress will not activate it until they are there. Upload the zip, activate, then go to Tools, Agent Tools for the endpoint, a button that issues an application password, and the client configuration filled in.
Added
refresh-abilities, which drops the compiled tool list so the next discovery rebuilds it. The list is cached against the active plugins and their versions, and accepting an agreement or connecting an account changes neither: WooCommerce Shipping goes from two tools to several dozen on accepting its terms, with an identical fingerprint either side, so the stale list was served for up to a day with nothing able to notice. The refusal for a call handed to the merchant now tells the agent to refresh and discover again once they report it done, and says that an unchanged list is not evidence they failed until it has been refreshed.- A write whose route declares no parameters is handed to the merchant instead of previewed. The gate cannot say what such a route expects, so the refusal names an admin screen, relays what the tool says it does, and lists anything the agent inferred and is sending anyway. That class is where accepting a terms of service, connecting a payment or shipping account and triggering a deposit all sit. The token still works for a merchant who reads the refusal and asks the agent to proceed.
woocommerce_agent_tools_self_serve_url, so the plugin that owns a route can send one of those calls to its own settings screen rather than the admin root. Returning an empty string removes the link; the route still declares no payload, so the refusal keeps saying so and names no screen.
Fixed
Cache::flush()documented itself as the manual refresh and had no caller, so the only way to rebuild the tool list was to wait out the day-long cache or delete the transient by hand.woocommerce_agent_tools_route_needs_confirmationdecided whether a derived tool published itsconfirmproperty and its not-reversible note, while the gate that enforces the hold read the route's own read/write annotation instead. A filter that asked for a read to be held left a tool promising a preview it never gave, and one that released a write produced a hold the tool had not advertised. A derived tool now records the decision its description was built from, and the gate honours that record for abilities in this plugin's own category; anything else is judged on its annotation as before.- A confirmation claimed for a call that was then refused before it ran, by the route's permission check or by input validation, left the merchant told their call had already been attempted and locked out of the same payload for ten minutes. The gate runs before either check, so it now hands the confirmation back when one of them refuses the call, on the ability path and on a direct REST write alike, and stops tracking it once the call is certain to run so a later refusal cannot re-arm a confirmation that has been spent.
- A payload that cannot be JSON-encoded, because it nests past the encoder's depth limit, hashed to the same confirmation token as every other such payload, so a preview of one would have authorised any of the others. The gate now refuses to confirm a payload it cannot identify.
- A confirmation token could authorise more than one call: two concurrent calls could both claim it, and a spent token was handed back to a caller that restarted the protocol. A payload that has already been confirmed is now refused with
wcat_confirmation_spentand status 409, with no token returned, while one that merely expired still gets a fresh preview. It matters most where there is no inverse, such as a second shipping-label refund. - A throw while re-reading a redacted secret left the re-entrancy flag set, and every later response in that request was returned to the agent unredacted.
- A cache entry holding a fingerprint but no descriptors made the compiler skip loading the full route table and then compile against a partial one, emitting a fraction of the store's tools.
- A tool whose route ran another ability stopped being recognised as internal traffic partway through, because the inner call reset a shared flag while the outer one was still running. The REST guard then began demanding a confirmation token for the rest of that outer call.
- A route registering POST, PUT and PATCH against one callback compiled into two tools that called the same handler with the same parameters, leaving an agent no way to choose between them. The edit verbs on one handler now yield one tool, named after what the route does: a collection keeps
create, an action route keeps its tail. A route registering POST and PUT as separate handlers keeps both, since those are different callbacks.
Changed
- agents.md tells a connecting agent who it is on this connection: the merchant's store manager, talking in the store's terms, and explicitly not a shopping assistant, since the tools here run with the connected user's capabilities over every order and customer rather than one shopper's own.
- agents.md says what to do after the merchant finishes a task in wp-admin: refresh the tool list before concluding anything from it.
- agents.md explains the class of call whose route states no payload, what the refusal says instead, and what to do with the admin screen it usually names.
- Drop the parameter list from every tool description. It repeated
input_schema, which get-ability-info returns in full, and named only the first ten parameters, so a tool taking twenty-three read as taking ten. Shortens whatdiscover-abilitiesreturns by 15.6%.
Internal
- Unit tests for the confirmation gate's token lifecycle, run with
composer test. The harness models WordPress's transient semantics rather than booting WordPress. - Move the classes to PSR-4 under
src/, in theWooCommerce\AgentToolsnamespace, grouped by responsibility (Route,Ability,Safety,Agent). The build now ships Composer's autoloader instead of a hand-maintained list of twentyrequire_oncelines, which was a silent fatal whenever a new class was forgotten. - Replace the static classes with constructor injection. Collaborators are passed in,
Pluginis the only place that callsnew, and the request-scoped state that lived in static properties now belongs to the object that owns it. - Class names change with the namespace:
WC_Agent_Tools_Gateis nowWooCommerce\AgentTools\Safety\Gate, and so on. The filters are unchanged, so anything hookingwoocommerce_agent_tools_*keeps working. - Stub the two PHP 8 string functions WordPress polyfills, so static analysis runs with no suppressed errors at all rather than ignoring them by pattern.
- Exclude the analysis-only stubs from the coding-standards run, and apply WooCommerce core's own sniff swap for a PSR-4 directory: the WordPress file-name rules off, the stricter class-name and file-match rules on.