Read-only Shopify catalogue and stock for Claude
shop-mcp is a single-file Model Context Protocol server that answers catalogue and stock questions about a Shopify store. It uses the Python standard library and nothing else. It cannot write. You can run the test suite before you give it a token.
uvx --from shop-mcp shop-mcp --self-test
That is the whole claim, and it runs before you hand over a token: no clone, no credentials, no network. What the count should be, and why it differs from a clone, is spelled out below.
Key takeaways
- Four tools, all read: product search, one product in full, stock per location for a SKU, and a low-stock list.
- No MCP SDK, no
requests, no GraphQL client. The install is the file. - The self-test needs no credentials and no network. A write path is not in the code.
- This page is the public build. A custom server over your own data is a separate, priced job on the services page.
Run it before you trust it
uvx --from shop-mcp shop-mcp --self-test needs no clone and no credentials, and reports 183 assertions rather than 200: manifest.json (5 assertions), llms-install.md (11) and README.md (1) are deliberately not shipped into site-packages, and every one of those checks skips rather than fails when its file is absent. The count moves, the verdict does not.
- 200 assertions in
self_test.py, runnable withpython3 shop_mcp.py --self-testfrom a clone. - 23 deliberate defects injected by
mutation_test.sh— a wrong pagination cursor, a swapped comparison, a dropped error branch — and all 23 turn the suite red. - Zero third-party packages, so the whole thing is readable in one sitting.
Those numbers are not typed onto this page by hand. They come from evidence.json, which is rewritten by running the suites in github.com/hello532/shop-mcp. If the suite moves, this page has to move with it or the site gate goes red.
What it will not do
- It will not create, update, or delete products, variants, or inventory.
- It will not touch orders, customers, or discounts.
- It will not send your catalogue anywhere except the Shopify Admin API and the stdio pipe to the host.
- It will not phone home. There is no telemetry.
The Admin token it wants is read_products and read_inventory. A write scope is unused. That is the blast-radius argument against a 55-tool server on a live store: feature count is the wrong axis when a bad prompt can edit the catalogue.
The four tools
search_products— what you sell that matches a query: identity and total stock.get_product— one product in full, every variant with SKU, price, and stock.check_inventory— stock for a SKU per location: available, committed, on-hand.low_stock_report— variants at or below a threshold, lowest first, and whether the scan ran out of page before it finished.
Four is a choice. A wider surface is easy and makes the model worse at picking.
Defects the suite is built to catch
A stdio MCP server fails invisibly when you run it yourself and fatally inside a host. Each of these has a named assertion:
- A diagnostic on stdout. One stray
print()corrupts the client's next parse. Diagnostics go to stderr; a test asserts stdout stays byte-empty. if msg.get("id")is falsy for zero, so a client numbering requests from zero has its first call silently dropped. Presence, not truthiness.- A tool that ran and failed must return a normal result with
isError: true. A JSON-RPC error is for a malformed request; the model never sees those. - An unquoted SKU.
sku:SH 1is a different query fromsku:"SH 1". The first silently matches the wrong variants. - A null quantity coerced to zero. Shopify returns
nullfor a variant that does not track inventory. Untracked and out of stock are different facts.
What is not verified
This has never been run against a live Shopify store. There is no credential in the repository and no recorded API session. The queries are written to the documented Admin GraphQL schema, and every path around them is tested against a transport double — but the doubles are a model of Shopify's behaviour, not Shopify. A README that blurs that line is asking to be trusted on the wrong thing.
The listing in the official MCP Registry is a different kind of fact: it validated that the io.github.hello532 namespace is mine before it would accept the entry. That record answers for itself — one record, status: active — rather than being a badge drawn here.
Install
On PyPI as shop-mcp 1.0.1. Source at github.com/hello532/shop-mcp. MIT licence.
export SHOPIFY_SHOP_DOMAIN=your-shop.myshopify.com
export SHOPIFY_ADMIN_TOKEN=shpat_... # read_products, read_inventory
uvx shop-mcp # or: pip install shop-mcp && shop-mcp
Claude Desktop, or any MCP host:
{
"mcpServers": {
"shop": {
"command": "uvx",
"args": ["shop-mcp"],
"env": {
"SHOPIFY_SHOP_DOMAIN": "your-shop.myshopify.com",
"SHOPIFY_ADMIN_TOKEN": "shpat_..."
}
}
}
}
With no credentials set it still completes a handshake and serves tools/list, then returns isError with the missing variable named. A host that cannot read tools/list reports a broken server and sends you looking in the wrong place.
If you want the same shape over your own data
This file is the worked example, not a product line. The same discipline — a stdio MCP server over data you already have, with a self-test suite and proof the suite catches injected defects — is a fixed-price job on the services page. Email coolun337@gmail.com. Nothing on this page needs paying for; issues and PRs are welcome either way.
uvx --from shop-mcp shop-mcp --self-test is the whole claim. If that is not green on your machine, nothing else on this page matters.