shopware-mcp

MCP serverDev tools

Query and safely manage a Shopware 6 shop: products, orders, customers, stock, audits, reports.

Unavailable. This server has no hosted endpoint yet, so ahel can't serve it.

Connect ahel once, and every AI you use reads what you have installed.

From the project's README

As published by bnymndev/shopware-mcp in README.md.


Introducing shopware-mcp

A Shopware 6 shop is about two hundred entities behind one Admin API. Ask an assistant "is everything okay with the shop?" and the honest answer takes seven searches with Criteria filters, three state machines by their technical names, a couple of aggregations, and an OAuth token it must never repeat back to you. Wire a model straight to that API and it gets all of it, including the right to PATCH a price because a prompt said so.

The Model Context Protocol turned "give the model real tools" into a one-line config change. It says nothing about what a good tool for a shop looks like: which of the two hundred entities matter on a Tuesday morning, what "stuck order" means, or that a stock correction should be shown before it is sent.

shopware-mcp is that layer. One small server that speaks MCP to the host and the Admin API to the shop, and knows Shopware well enough to answer in one call what used to take an afternoon in the admin:

Curated toolsProducts, orders, customers, categories, promotions, plugins, stock, sales channels: sixteen tools that return compact JSON with exact totals, descriptions written for a model, and Shopware's own Criteria filters. No invented query language.
An auditshop_audit runs eleven checks in one call: paid orders that never shipped, unpaid orders going stale, shipped orders never completed, products out of stock, without a cover or without a delivery time, promotions past their end date, channels in maintenance, storefronts missing a legal page, extensions with updates waiting, and which EU duties look covered by an installed extension. Prioritised, with samples and a hint per finding.
A reportsales_report asks Shopware to aggregate: gross, net, average order, revenue per currency and channel, orders per state, a day/week/month timeline, the top products and, on request, the change against the period before. The figures were checked against SQL on the same database.
An escape hatchentity_schema describes any of the 200+ entities, a plugin's custom entities included, and entity_search queries them with the same filters. Entities that hold credentials are refused, secrets in the rest are scrubbed.
A brakeRead-only unless you start it with --allow-write. Even then every write is a dry run that shows the exact request first, and a write budget can cap how many real writes a process may make. Ship, mark paid, remind, refund, correct stock, note, generate a document: eight narrow writes, nothing else. Secrets never appear in output, logs or errors.

Shops are not identical, so the tool list is not either: at startup the server looks up which extensions are installed and registers extra tools for the ones it knows. A plain shop gets the core set. A shop with more plugins gets a bigger agent, without configuration.


See it work

Every recording on this page is real output from the server against a Shopware 6.7.13 test shop with generated demo data, replayed from the transcripts in docs/demo/. Tool calls and results are verbatim, shortened to fit the screen. The prose is what an MCP host says with them.

One question, nine checks. Three paid orders are still waiting for shipment, the storefront is in maintenance, a summer promotion outlived August. The answer names order numbers and amounts, and offers the safe next step.

Numbers the shop computed itself. Totals, channels, states, a monthly timeline and the top product for eight months, from one call. No order was paged through; Shopware's aggregations did the work.

No tool for that? There is a schema for that. Manufacturers have no dedicated tool. The agent reads the entity's schema, spots mediaId, and filters on it. The same path reaches every other entity, custom ones included.

Writes show their hand first. With --allow-write, a stock correction comes back as the request it would send. Only an explicit dryRun: false touches the shop, and the result is re-read from Shopware.

A shop with more plugins gets a bigger agent. The core tools are ready immediately. The extension lookup finishes in the background, four tools appear, the host is told to refresh its list, and a compliance question has an answer.

Know before the agent finds out. shopware-mcp doctor probes what the integration may read, reads its role for the write privileges where it can, and names the missing one per tool. An administrator gets a wall of ticks; a support-desk role gets told exactly what to grant.


What's in the box

Sixteen curated toolsproducts_search, orders_get, customers_search, stock_get, promotions_list, plugins_list and friends. Each takes { term?, filter?, sort?, page?, limit?, fields? } and returns { total, page, limit, items }.
Health auditshop_audit with tunable thresholds (stuckOrderDays, lowStockThreshold, maxItems). Eleven checks including legal pages per storefront and delivery times, prioritised findings, a hint per finding, and an EU duty overview that names duties and deadlines, never products.
Sales reportsales_report for any period, by day, week or month, optionally per sales channel, cancelled orders excluded. compareWithPrevious adds the preceding period and the change in orders, revenue and average order value. Top products resolved by exact product id so ties cannot skew revenue.
Any entityentity_schema lists all entities or describes one: fields, types, flags, associations. entity_search queries it. Long text values are truncated, secrets scrubbed, credential entities refused.
Plugin-aware toolsThe server detects installed, active extensions and adds tools for the ones it knows. First pack: Merqo. Off with --no-extensions.
Documentsorder_documents_list, order_document_create (invoice, delivery note, credit note, cancellation, by Shopware's own generator) and document_download, which hands the PDF to the host as an embedded resource while the model sees only the metadata.
Guarded writesstock_set, product_update, order_state_transition, order_delivery_transition (ship, with tracking codes), order_transaction_transition (mark paid, remind, refund), order_note (internal comment), order_document_create, promotion_toggle. Registered only with --allow-write, dryRun: true by default, the re-fetched entity on a real write. SHOPWARE_MCP_MAX_WRITES caps real writes per process.
Doctor and initshopware-mcp doctor says per tool whether this integration can use it and which privilege is missing. shopware-mcp init tests the credentials and prints or writes the config for Claude Desktop, Claude Code, Cursor, VS Code or Zed.
Resources and promptsshopware://shop, shopware://sales-channels, the templates shopware://order/{orderNumber} and shopware://product/{productNumber} so a host can attach a record as context, and three prompts: order_summary, low_stock_report and weekly_review.
Shopware's vocabularyFilters are Shopware Criteria filters (equals, contains, range, equalsAny) on Shopware field paths, including associations like manufacturer.name. State names are the technical names you already know.
Portable schemasEvery tool schema is checked to avoid constructs that some MCP clients misread, so the same server works in every host.
A solid clientOAuth client credentials with early token refresh, one retry on 401 and on 429/5xx with Retry-After, a per-request timeout, exact totals, inheritance and language headers, a cached entity schema.
Two transportsstdio for desktop hosts, stateless Streamable HTTP for everything else, with an optional bearer token.
Packaged four waysnpm with build provenance, a Docker image on GHCR for amd64 and arm64, a one-click .mcpb bundle for Claude Desktop that asks for the credentials and a write budget, and a listing in the official MCP registry.

Who it is for

  • You run a shop and want to ask it questions instead of clicking through the admin. Stuck orders, low stock, last month's numbers, one prompt each.
  • You run an agency and look after many shops. The core here covers one shop per server; the multi-shop, audited, hosted version is what the author builds for clients (see Open core).
  • You build Shopware plugins and want your custom entities reachable by an agent today, and your own tools registered tomorrow. entity_search does the first; one file under src/extensions/ does the second.
  • You build agents and want an MCP server that behaves: compact output, honest totals, dry runs, no surprises in the schema.

60 seconds

1. Create an Integration in your Shopware admin: Settings → System → Integrations → Add integration. Copy the access key ID and the secret; the secret is shown once. For a dev shop tick Administrator, for production give it a read role (see permissions).

2. Let the wizard test the credentials and write the host config for you:

npx shopware-mcp init                  # asks for URL, key and secret, tests them, prints the config
npx shopware-mcp init --for claude-desktop --write   # or merges it into the host's config file
npx shopware-mcp doctor                # which tools can this integration use, and what is missing

Or run the server by hand:

export SHOPWARE_URL=https://shop.example.com
export SHOPWARE_CLIENT_ID=SWIA...
export SHOPWARE_CLIENT_SECRET=...

npx shopware-mcp                       # stdio (default)
npx shopware-mcp --http --port 3333    # Streamable HTTP on http://127.0.0.1:3333/mcp
npx shopware-mcp --allow-write         # also register the guarded write tools

3. Connect a host (or let init --write do it):

Download shopware-mcp.mcpb from the latest release and double-click it, or add this to claude_desktop_config.json:

{
  "mcpServers": {
    "shopware": {
      "command": "npx",
      "args": ["-y", "shopware-mcp"],
      "env": {
        "SHOPWARE_URL": "https://shop.example.com",
        "SHOPWARE_CLIENT_ID": "SWIA...",
        "SHOPWARE_CLIENT_SECRET": "..."
      }
    }
  }
}
claude mcp add shopware \
  -e SHOPWARE_URL=https://shop.example.com \
  -e SHOPWARE_CLIENT_ID=SWIA... \
  -e SHOPWARE_CLIENT_SECRET=... \
  -- npx -y shopware-mcp

They all take the same three fields. Cursor reads .cursor/mcp.json, VS Code .vscode/mcp.json (under servers instead of mcpServers), Zed its context_servers block:

{
  "mcpServers": {
    "shopware": {
      "command": "npx",
      "args": ["-y", "shopware-mcp"],
      "env": {
        "SHOPWARE_URL": "https://shop.example.com",
        "SHOPWARE_CLIENT_ID": "SWIA...",
        "SHOPWARE_CLIENT_SECRET": "..."
      }
    }
  }
}

Hosts that read the official MCP registry find it as io.github.bnymnDev/shopware-mcp.

docker run --rm -p 3333:3333 \
  -e SHOPWARE_URL=https://shop.example.com \
  -e SHOPWARE_CLIENT_ID=SWIA... -e SHOPWARE_CLIENT_SECRET=... \
  ghcr.io/bnymndev/shopware-mcp

The image serves Streamable HTTP on http://127.0.0.1:3333/mcp. Point any HTTP-capable host at that URL. Add -e SHOPWARE_MCP_HTTP_TOKEN=<random secret> and the endpoint requires Authorization: Bearer <secret>; without a token, keep it on localhost or behind a proxy that authenticates (self-hosting notes).

4. Ask. The first useful question is usually "Is everything okay with the shop?"


Ask it anything

You sayThe agent calls
"Is everything okay with the shop?"shop_audit
"How did we do in August?"sales_report { from, to, interval: "week" }
"Which products are below 5 in stock?"products_search with a range filter, or the low_stock_report prompt
"Summarise order 10042 for a support reply."orders_get, or the order_summary prompt
"Which customers ordered more than ten times?"customers_search with a range filter on orderCount
"Is the PayPal plugin up to date?"plugins_list
"Which manufacturers have no logo?"entity_schema then entity_search on product_manufacturer
"Set the stock of SW10084 to 40."stock_set, dry run first, then for real
"Order 10042 shipped with DHL, tracking 00340434."order_delivery_transition { transition: "ship", trackingCodes }
"The bank transfer for 10038 arrived."order_transaction_transition { transition: "paid" }
"How was last week compared to the week before?"sales_report { compareWithPrevious: true }, or the weekly_review prompt
"Send me the invoice for 10042."order_documents_list, then document_download returns the PDF
"Note on 10042: customer called, ships Monday."order_note
"Which of my tools will fail with this integration?"not a tool: npx shopware-mcp doctor

Filters, in one screen

Every search tool takes the same filter array, and every entry is a Shopware Criteria filter:

{ "type": "equals",    "field": "active",                                    "value": true }
{ "type": "range",     "field": "stock",                                     "value": { "lt": 5 } }
{ "type": "range",     "field": "orderDateTime",                             "value": { "gte": "2026-06-01" } }
{ "type": "equals",    "field": "transactions.stateMachineState.technicalName", "value": "paid" }
{ "type": "contains",  "field": "name",                                      "value": "shirt" }
{ "type": "equalsAny", "field": "id",                                        "value": ["…", "…"] }
{ "type": "equals",    "field": "manufacturer.name",                         "value": "Acme" }

Anything you can filter in the Admin API works here too, associations included. Need a raw field that the compact output leaves out, such as customFields, ean or weight? Pass fields: ["customFields", "ean"] and it is added to every item. Reading a shop in another language? Set SHOPWARE_LANGUAGE_ID. The full cheat sheet has more.


Tools

ToolAccessPurpose
shop_inforeadShop info
sales_channels_listreadList sales channels
products_searchreadSearch products
products_getreadGet product
orders_searchreadSearch orders
orders_getreadGet order
order_documents_listreadList order documents
document_downloadreadDownload document PDF
customers_searchreadSearch customers
customers_getreadGet customer
categories_listreadList categories
promotions_listreadList promotions
plugins_listreadList plugins and apps
stock_getreadGet stock
sales_reportreadSales report
shop_auditreadShop health audit
entity_schemareadEntity schema
entity_searchreadSearch any entity
stock_setwrite (guarded)Set stock (guarded)
product_updatewrite (guarded)Update product (guarded)
order_state_transitionwrite (guarded)Transition order state (guarded)
order_delivery_transitionwrite (guarded)Transition delivery state (guarded)
order_transaction_transitionwrite (guarded)Transition payment state (guarded)
order_notewrite (guarded)Add internal order note (guarded)
order_document_createwrite (guarded)Create order document (guarded)
promotion_togglewrite (guarded)Toggle promotion (guarded)

Every parameter of every tool: docs/tools.md. Searches return { total, page, limit, items } with exact totals, limit is capped at 50, and errors come back as { error: { status, code, detail } } so the model can react instead of guessing.

Resources: shopware://shop, shopware://sales-channels, shopware://order/{orderNumber}, shopware://product/{productNumber}. Prompts: order_summary, low_stock_report, weekly_review.

Plugin-aware tools

At startup the server asks the shop which extensions are installed and active, in the background, and registers extra tools for the ones it knows. A shop that does not answer simply keeps the core tools. --no-extensions turns the whole mechanism off.

Today one suite is supported, Merqo, which adds merqo_health, merqo_einvoice_inbox, merqo_returns_search and merqo_abandoned_carts. Shops without it never see those tools, and nothing in the core tools changes either way. Support for another vendor's extensions is one file under src/extensions/; pull requests are welcome.


Safety

  • Read-only by default. Without --allow-write (or SHOPWARE_MCP_ALLOW_WRITE=true) the write tools are not registered. An agent cannot discover what it cannot call.
  • Every write is a dry run first. stock_set, product_update, order_state_transition, order_delivery_transition, order_transaction_transition, order_note, order_document_create and promotion_toggle default to dryRun: true and return { dryRun: true, wouldSend: { method, url, body } }, a list when one call needs several requests. A real write returns the re-fetched entity.
  • A write budget. SHOPWARE_MCP_MAX_WRITES=20 refuses the twenty-first real write of a process with WRITE_BUDGET_EXHAUSTED; dry runs stay free. No prompt can lift it.
  • Narrow writes. product_update touches name, description, active and one currency's price. The transition tools only move state machines; nothing moves money. Documents come from Shopware's own generator and are never sent by this server. Nothing else is writable.
  • Scrubbed reads. entity_search strips passwords, keys, tokens and hashes from every payload and refuses entities that exist to hold credentials or system internals: users, integrations, ACL roles, apps, system config.
  • No secrets anywhere. Credentials never appear in output, logs or error messages. Logs go to stderr only, at error level unless you ask for more.
  • No telemetry. The server talks to your shop and to your host. Nothing else.
  • HTTP transport. Set SHOPWARE_MCP_HTTP_TOKEN and every call to /mcp needs that bearer token, compared in constant time. Without it, bind to localhost (the default) or put it behind a reverse proxy that authenticates; the server warns when it is reachable further without a token.
  • Requests time out. A shop that stops answering costs one request 30 seconds (SHOPWARE_MCP_TIMEOUT_MS), not the whole session.

Found something? See SECURITY.md.


Configuration

Shortened here. Read the whole README on GitHub.

Signals

GitHub stars
57
Forks
7
Last commit
Sep 2026
Weekly downloads
584
Advanced
Delivery
shopware-mcp MCP server → your ahel gateway (mcp.ahel.ai) → every connected AI client.
Catalog kind
mcp-server
Gateway key
io-github-bnymndev-shopware-mcp
Source
github.com/bnymndev/shopware-mcp