WooCommerce + MCP: Give AI Agents Read-Only Store Access
It's Monday morning and you run a small WooCommerce shop. Before coffee you want to know three things: which orders are stuck in "processing", which products have sold out, and whether that customer who emailed on Saturday actually placed an order. That's fifteen minutes of clicking through wp-admin. Or one sentence to an AI agent, if the agent can see your store.
As of WooCommerce 11.2.0 (released October 7), it can, without a custom plugin. WooCommerce now ships native MCP support, so Claude, Cursor or any other MCP client can query and manage your store. It's labeled a developer preview, and it can delete products, so this guide sets it up the careful way: a dedicated user, a read-only role, and a server that exposes only the read-only tools.
How It Works Under the Hood
WooCommerce's MCP support sits on two WordPress building blocks it bundles:
- The Abilities API: plugins register "abilities", which are named operations with input and output schemas and a permission check.
- The MCP Adapter: it turns abilities into MCP tools and serves them over HTTP from the WordPress REST API.
WooCommerce 11.2 registers seven abilities, each tagged with MCP hints that tell the agent how dangerous a call is:
| Ability | What it does | Annotations |
|---|---|---|
| woocommerce/products-query | Search and filter products | Read-only |
| woocommerce/orders-query | Search and filter orders | Read-only |
| woocommerce/product-create | Create a product | Writes |
| woocommerce/product-update | Edit a product | Destructive |
| woocommerce/product-delete | Delete a product | Destructive |
| woocommerce/order-update-status | Change an order's status | Destructive |
| woocommerce/order-add-note | Add a note to an order | Writes |
Every call runs as a real WordPress user, and each ability checks that user's capabilities. Reading orders requires read_private_shop_orders, for example. That's the lever we'll pull.
There's one more detail worth knowing. WordPress's default MCP server, at /wp-json/mcp/mcp-adapter-default-server, doesn't list those seven abilities as tools. It exposes three meta-tools (discover, get info, execute), and the agent finds abilities at runtime. That's convenient, but it means the agent sees everything public, including delete. We'll build a smaller server instead.
Step 1: One Small Must-Use Plugin
Must-use plugins load automatically and can't be switched off from wp-admin, which is exactly what you want for access control. Create wp-content/mu-plugins/store-mcp.php:
<?php
/**
* Plugin Name: Store MCP (read-only)
*/
// 1. Turn on WooCommerce's MCP integration (developer preview).
add_filter( 'woocommerce_features', function ( $features ) {
$features['mcp_integration'] = true;
return $features;
} );
// 2. A role that can read products and orders, and nothing else.
add_action( 'init', function () {
if ( ! get_role( 'mcp_readonly' ) ) {
add_role( 'mcp_readonly', 'MCP Read-Only', array(
'read' => true,
'read_private_products' => true,
'read_private_shop_orders' => true,
) );
}
} );
// 3. An MCP server that exposes only the two read-only tools.
add_action( 'mcp_adapter_init', function ( $adapter ) {
// WooCommerce does the same: the adapter's validator rejects some of its schemas.
add_filter( 'mcp_validation_enabled', '__return_false', 999 );
$adapter->create_server(
'store-readonly',
'mcp',
'store-readonly',
'Store (read-only)',
'Query products and orders',
'1.0.0',
array( \WP\MCP\Transport\HttpTransport::class ),
\WP\MCP\Infrastructure\ErrorHandling\ErrorLogMcpErrorHandler::class,
null,
array( 'woocommerce/products-query', 'woocommerce/orders-query' )
);
remove_filter( 'mcp_validation_enabled', '__return_false', 999 );
} );
Your new server lives at https://yourstore.com/wp-json/mcp/store-readonly, and its tool list has exactly two entries. Even if a prompt injection hidden in a product review convinces the agent to "delete all products", there's no delete tool to call, and the user behind it couldn't delete anything anyway. That's two independent locks.
Step 2: A Dedicated User and an Application Password
In wp-admin, go to Users → Add New, create a user called mcp-agent with the MCP Read-Only role, then open its profile and create an Application Password under the section of the same name. Copy it: WordPress shows it only once.
Never use your admin account for this. Application Passwords can be revoked one by one, so if a laptop with the config goes missing, you kill that one password and nothing else. Two requirements: the site must use HTTPS, and permalinks must be anything other than "Plain".
Step 3: Connect Your Agent
The MCP client talks to WordPress through Automattic's small local proxy, which turns stdio into authenticated HTTPS calls. In Claude Code:
claude mcp add \
--env WP_API_URL=https://yourstore.com/wp-json/mcp/store-readonly \
--env WP_API_USERNAME=mcp-agent \
--env WP_API_PASSWORD='xxxx xxxx xxxx xxxx xxxx xxxx' \
woocommerce_store \
-- npx -y @automattic/mcp-wordpress-remote@latest
For Claude Desktop or Cursor, the same values go in the mcpServers block of the config file, with npx as the command. Don't commit that file anywhere: it contains the password.
Now ask questions in plain English: "List orders in processing status created before Monday", "Which products are out of stock or on backorder?", "Has jane@acme.com ordered anything since October 1?" The agent turns each one into an orders-query or products-query call with filters (status, stock status, billing email, date range) and answers in seconds. Anything the filters can't express takes more calls, or isn't possible yet.
When You're Ready to Let It Write
Once you trust the setup, widen it on purpose, one step at a time. Add woocommerce/order-add-note to the server's tool list first: notes are low risk and give the agent a way to leave its reasoning on the order. Both notes and status changes check edit rights on the order, so the role also needs edit_shop_orders and edit_others_shop_orders. Add order-update-status only after notes have behaved for a while. Leave product-delete out entirely. Nobody needs a chatbot deleting products.
Remember the label, too: the docs say APIs "may change in future releases". Test after every WooCommerce update before you depend on it.
Running It on Elestio
On Elestio, WooCommerce runs as a fully managed service with HTTPS already set up. WooCommerce is open source, so you pay only for the VM: a 2 vCPU / 4 GB server (about $16/month on Netcup) is plenty for a small shop. Backups, updates and monitoring are included. The site runs in Docker Compose under /opt/app/, and from the VM terminal find /opt/app -maxdepth 4 -type d -name wp-content shows you where to drop the mu-plugin.
Troubleshooting
The endpoint returns 404. Permalinks are set to "Plain", or the mu-plugin isn't in wp-content/mu-plugins/ itself (subfolders aren't loaded automatically).
401 or "Sorry, you are not allowed". Wrong username, or you pasted the account password instead of the Application Password. Check that the user has the MCP Read-Only role.
The tool list is empty. The mcp_integration flag didn't take effect, or you're on a WooCommerce version older than 11.2. Look in WooCommerce → Status → Logs for entries from woocommerce-mcp.
Product questions work, order questions fail. The role is missing read_private_shop_orders. If you created mcp_readonly earlier with different capabilities, the get_role() guard won't update it: delete the role (or the user's role assignment), reload any page so the mu-plugin recreates it, and reassign it.
One last reminder: order data includes names, emails and addresses, and everything the agent reads goes to whichever model provider you use. Pick that provider accordingly.
Thanks for reading ❤️ See you in the next one 👋