Alza Mcp

io.github.lukabudikv0.4.0更新于 Oct 7, 2026

Unofficial MCP server for Alza.cz: catalog search plus token-guarded account and checkout.

概览

AI 生成的概览

非官方 Alza.cz 购物服务器,让助手搜索商品目录、比较商品、查找自提点,并管理购物车与结账。

功能
它提供 Alza.cz 商品目录工具,例如 search_products、get_product、compare_products、get_product_reviews、recommend_alternatives、find_pickup_points、list_categories、get_deals 和 autocomplete,以及 PC 配件配置工具。工具按工具集分组,默认只启用 catalog 和 auth,其他工具集(购物车与结账、账户管理、订单与支付、评价与订阅、监控、聊天、原始移动端读取)需通过 set_toolset 启用。目录页面用无头浏览器抓取,账户与结账流程调用逆向得到的移动端和网页 API。
适用场景
适合让助手在 Alza.cz 上调研商品、价格、库存、评价和自提点,或在真实 Alza 账户上准备并提交订单。面向个人或研究用途,不适合大规模使用。
运行要求
通过 npx alza-mcp 以 stdio 在本地运行,需要 Node.js。首次调用会下载 Playwright 的无头 Chromium(约 92 MB);postinstall 会尝试配置可选的 Python curl_cffi 边车。目录功能不需要环境变量或密钥;账户功能需要 OAuth 登录,可选变量包括 ALZA_BASE_URL、ALZA_CDP_URL、ALZA_HEADLESS 和 ALZA_TOKEN_FILE。可选的 HTTP 模式仅绑定本机。
安装前请注意
该项目为非官方,并绕过 Cloudflare 机器人防护,Alza 的使用条款可能禁止此类行为。结账、下单、支付、注册和删除账户工具会操作真实账户并花费真实金钱;订单具有约束力,取消不保证成功。携带凭据的工具如 register、change_password、phone_change、email_change,以及 place_order、cancel_order、pay_after_order、delete_account,需要来自 prepare_mutation 或 checkout_preview 的一次性令牌,但令牌只能防止助手误调用。登录在浏览器中通过 OAuth PKCE 完成;ALZA_TOKEN_FILE 保存登录信息。HTTP 模式没有内置认证或 TLS,除非设置 ALZA_HTTP_ENABLE_ACCOUNT,否则账户类工具集被锁定。

安装

在 SourceWeft 中

  1. 打开 控制台中的 Alza Mcp,将其添加到工作区。
  2. 为需要使用其工具的对话启用该服务。

Desktop only,通过 STDIO。 STDIO 服务会启动本地进程,因此需要 SourceWeft 桌面宿主。

其他 MCP 客户端

参照 仓库 中的启动说明。

README

alza-mcp

Let your AI agent shop on Alza.cz — Central Europe's largest e-commerce store.

[npm version] [CI] [License: MIT] [TypeScript] [Playwright] [MCP]

alza-mcp is an unofficial Model Context Protocol server that gives Claude (or any MCP-aware agent) an interface to Alza through browser-based catalog scraping and reverse-engineered mobile/web APIs: search products, pull full detail, read reviews, use anonymous/account data, manage a cart, select delivery/AlzaBox pickup, preview checkout, and submit an order only with an explicit one-time confirmation token.

[Animated recording of a real Claude Code session: search_products finds wheel cleaners under 600 Kč, get_product shows price and stock, find_pickup_points lists Prague showrooms]

Real session, catalog toolset only, no account. Re-record: docs/demo-recording.md. Static version: docs/demo.svg.

Ask: "Find me the best pro-grade wheel cleaner under 600 Kč and tell me where I can pick it up in Prague." The agent calls search_products → get_product → find_pickup_points and gives you a real answer with real prices and a real address.

[!IMPORTANT] This project is unofficial — not affiliated with, endorsed by, or sponsored by Alza.cz a.s. It's a community wrapper for personal/research use. Read the disclaimer before deploying or sharing widely.


Quick install

One-click install

[Install in Cursor] [Install in VS Code]

Both buttons install the same thing as the manual config below: npx -y alza-mcp, no environment variables, no secrets. The first tool call downloads Playwright's headless Chromium (~92 MB, ~30 s); every call after that is a few seconds. For Claude Desktop, download the one-click alza-mcp-<version>.mcpb bundle from the latest release (attached from the next release onward) and open it, or use the JSON config below.

Claude Code

bash
claude mcp add alza --scope user -- npx -y alza-mcp

That's it. Restart Claude Code, type /mcp to confirm, and start asking. First call takes ~30 s while Playwright downloads its headless Chromium browser (~92 MB) — every call after that is a few seconds.

Claude Desktop

Add to ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):

json
{  "mcpServers": {    "alza": {      "command": "npx",      "args": ["-y", "alza-mcp"]    }  }}

Restart the app. Same first-call download.

Cursor / Continue / any MCP client

Same shape — command: "npx", args: ["-y", "alza-mcp"]. Stdio transport, standard MCP everywhere.


What you can ask

A real session captured during testing:

You: Find me the best pro-grade wheel cleaner on Alza, around 500 Kč. I want a detailer-tier brand.

Claude: (calls search_products "čistič disků kol" sort=rating, then get_product on the top picks)

Top three from the live catalog:

#ProductBrandVolumePrice★
1Sonax Xtreme Full EffectSonax 🇩🇪750 ml559 Kč4.8
2Kenotek Wheel Cleaner UltraKenotek 🇧🇪1 L455 Kč4.8
3Auto Finesse Reactive 1LAuto Finesse 🇬🇧1 L599 Kč4.4

Pick: Sonax Xtreme Full Effect 750 ml — the de-facto detailer recommendation. It's iron-fallout reactive (turns purple on contact with brake-dust particles so you can watch it work), Sonax is a German workshop standard, and it's in stock.

That's the agent calling four MCP tools across two parallel searches and synthesizing real Alza data. No hallucinated SKUs.


What it does

With 63 domain tools (65 including list_toolsets and set_toolset), listing every tool on every tools/list call would front-load an agent's context with dozens of tools it may never touch in a given conversation. So they're grouped into toolsets, and only two are enabled by default, exposing 12 domain tools plus the two toolset controls:

ToolsetEnabled by default?Covers
catalog✅Search, product detail, side-by-side comparison, reviews, categories, pickup-point lookup
auth✅OAuth handshake, account status, the mutation-token issuer
basket_and_checkout—Cart, delivery/pickup selection, checkout, order placement & cancellation
account_management—Profile, contacts, addresses, registration, credential/identity changes
orders_and_payments—Order history, payment methods, after-order payments, claims, documents
reviews_and_subscriptions—Reviews, complaints, AlzaSubscription, attachments, EAN lookup
watchdogs—Alza's native price-drop / back-in-stock watchdog (list, set, delete)
chat—Alza's in-app chatbot
pc_builder—Compatibility-checked PC parts lists: pc_build_check, pc_build_suggest
advanced_raw—mobile_read, the untyped escape hatch

Call list_toolsets to see every group and set_toolset({id, enabled: true}) to turn one on before using its tools — e.g. enable basket_and_checkout before adding something to a cart. This is standard MCP progressive disclosure (RegisteredTool.enable()/.disable(), which fires the normal tools/list_changed notification) — no functionality is removed, it's just not all visible at once.

Catalog tools:

ToolPurpose
search_productsKeyword search, price/stock/screen-size filters, and bounded client-side sorting; brand/attribute filters use category pages and ignore query
get_productFull detail for one product — price, availability, brand, image, URL
compare_products2–6 products side by side — one aligned table of price, availability, rating and every spec row; optional summarize: true verdict via MCP sampling when the client supports it
get_product_reviewsAggregate rating + review count + individual reviews (author, date, rating, body, pros/cons) via the reviews API
recommend_alternativesCheaper / better-rated / same-brand alternatives to a product (Alza's own alternatives list, same-category search fallback)
find_pickup_pointsNearest AlzaBox lockers and AlzaShop showrooms by postal code, merged by distance, with opening hours, no cart needed. It can't tell whether a specific product fits an AlzaBox; use delivery_options for that
list_category_filtersCategory brands (brands[].valueId) and attribute facets with live ids/counts — use producer_ids or filters with category_id ({param_id, value_id} for checkbox facets, {param_id, min?, max?} for slider ranges such as screen size or refresh rate); unsupported URL filters return an error
get_dealsDiscounted products (alza.cz only) with current/original price and discount % computed from observed prices — scans category listing pages for a category_id, or popular categories when omitted
list_categoriesTop-level categories, or real subcategories when parent_id is supplied — feed the returned ids into search_products
autocompleteSearch-box suggestions over plain HTTP (no page render): phrases, categories, brands and products with ids/codes — refine a messy Czech query before search_products
product_by_eanLooks up catalog products by barcode/EAN (the app's camera barcode-scan API, AT3; read-only, no account required; enable reviews_and_subscriptions)

PC builder tools (enable pc_builder):

ToolPurpose
pc_build_checkChecks a parts list (Alza codes). Checks socket, RAM generation/slots, PSU wattage + headroom, GPU length and cooler height/radiator vs case, form factors, and display output. Returns prices, total, stock, and one verdict per rule with the spec values used
pc_build_suggestProposes a compatible build within a CZK budget from Alza's real component categories (gaming / workstation / office, pinned fixed_parts, bounded detail fetches)

Account and checkout tools:

ToolPurpose
auth_startCreates a mobile-API OAuth PKCE authorization URL
auth_exchangeExchanges the returned authorization code for mobile-API tokens
auth_discoveryReads live OIDC metadata from identity.alza.cz
mobile_readReads fixed APK-confirmed catalog, navigation, account, order-history, list, branch, alternative-product, basket, cost-estimate, web after-payment-dialog, web zip-code (WCF GetZipCodes twin), and chatbot-navigation capabilities
prepare_mutationCreates a one-time token for a fixed, source-confirmed mutation without sending a request
mutate_listExecutes a validated APK-confirmed low-risk mutation (lists, coupons, basket, country/ISIC, gift, watchdog, feedback, discussion) with that token
account_statusChecks whether a mobile API access token is loaded
cartReads the current cart and total
add_to_cartAdds a product by Alza code
delivery_optionsReads delivery + AlzaBox/pickup options from the APK getDeliveryPaymentGroups endpoint
select_pickup_pointDespite the name, returns the delivery → payment associations from getDeliveryAssociations (which payments fit a delivery, and the delivery fee under each). It does not pick a pickup point: re-tested on an authenticated cart on 2026-10-06. To choose an AlzaBox, use web_pickup_places → web_place_order with parcel_shop_id.
checkout_previewPreviews checkout and returns a one-time confirmation token
cancel_orderCancels an order part using its cancel form, a reason, and a one-time prepare_mutation token
place_orderRuns the mobile API order sequence only when supplied the preview token and required API payloads
web_pickup_placesReads the live web pickup family (AlzaBox/branches/24-7 availability, place list, place detail) for web-checkout delivery selection (read-only)
web_add_to_cartAdds a product to the live web HATEOAS basket (basket/v1/items, visitor-keyed) and returns the extracted basket id
web_cartReads the live web checkout cart state + item list for a basket id from web_add_to_cart (read-only)
chat_navigationReads the live chatbot HATEOAS navigation (chatbotapi.alza.cz, server-provided chat actions; read-only)
chat_sendOpens/continues a chatbot session with page context (session-scoped, visitor-keyed; returns {configuration, showChat})

User-management, payments, orders, and post-purchase tools:

ToolPurpose
profileReads the authenticated profile + address book (APK getUserData)
contactsReads the account contact list
registerRegisters a new Alza account (credential-bearing, one-time token)
address_upsertCreates/edits a delivery address through the server-provided address form
address_deleteDeletes a delivery address via its per-address action
address_searchFollows the server-provided address-search action (read-only)
payment_methodsLists payment methods from the APK delivery-payment-group endpoint
after_order_paymentsLists after-order payment options for an order part
pay_after_orderExecutes an after-order payment (APK AfterOrderRequestBody, one-time token)
web_place_orderPlaces an order through the live-verified legacy web WCF pipeline (SaveOrder2→3, 113-gate retry, CheckOrder4, SendOrder4; one-time token) — the working submission path while mobile sendOrder3 500s
web_pay_after_orderExecutes a web after-order payment through the live-verified WCF CreateAfterPayment (one-time token)
orderReads a user order (+ optional part detail, milestones, invoice refs)
review_submitSubmits a product review through the server-provided review form
complaint_claimsLists warranty claims via the server-provided claims action
subscription_overviewReads AlzaSubscription overview via the server-provided subscription action
subscription_activateActivates AlzaSubscription (one-time token)
subscription_update_installmentChanges the installment plan (one-time token)
upload_attachmentUploads image attachments via the multipart server-provided action (one-time token)
order_searchSearches the account's orders by term (OR6; read-only)
order_archiveReads the account's archived orders (OR7; read-only; the "Skrýt zrušené" include/hide-cancelled toggle)
order_documentDownloads an order invoice/document from its server-provided href (OR10; origin-validated to the Alza host family)
gdpr_infoReads the GDPR section + export dialog (A17; read-only — where the data export will be sent)
claim_detailReads one warranty claim's detail via its server-provided action (K2; read-only)
change_passwordChanges the account password (A14; one-time token; logs the user out of every device)
two_factor_setEnables/disables SMS two-factor (A15; one-time token)
phone_changeChanges the contact phone number (A16; one-time token)
email_changeChanges the contact email (A16 sibling; one-time token)
delete_accountDeletes the account (A18; one-time token; irreversible — disposable accounts only)
watchdog_listLists the account's Alza watchdogs: price-drop and back-in-stock alerts (B9a; read-only; no email in the output)
watchdog_setSets a watchdog on a product (max_price and/or track_stock). Alza emails the account when the condition is met (B9; one-time token)
watchdog_deleteDeletes a watchdog by watchdog_id or commodity_id (B9b; one-time token)

High-impact mutations require one-time confirmation tokens (checkout_preview for mobile place_order, prepare_mutation for the other guarded mutations); the full route inventory, exposure decisions, and verification labels live in docs/mobile-endpoint-coverage.md.

OAuth sign-in happens outside the MCP; auth_exchange exchanges the returned code and the server holds access/refresh tokens in memory or loads them from the configured token file.

"Při přihlášení došlo k chybě." after signing in? The sign-in usually worked. Alza redirects to alza://identity?code=…&state=…, which a desktop browser can't open, so the page stalls and a 40-second timer in Alza's login page shows that message. Before signing in, open DevTools and turn on Network → Preserve log. After you sign in, copy the alza://identity?code=… URL from the redirect's Location header, or from the Console error about failing to launch alza://. Pass the whole URL to auth_exchange as code. The code expires quickly, so exchange it right away. Registration and credential-change tools do accept passwords or verification codes as arguments, guarded by one-time confirmation tokens. Account/cart/order tools issue API requests and can fall back to browser-backed requests when challenged; they do not automate checkout forms.

Checkout paths: web_place_order submits the cart populated by add_to_cart, after delivery_options and any cart-scoped web_pickup_places lookup. The web_add_to_cart → web_cart HATEOAS basket is separate. The mobile place_order route was blocked by server-side HTTP 500 in the recorded live tests; the legacy WCF path was live-verified. See known limitations for dated evidence.

Mobile API environment variables:

Env varPurpose
ALZA_API_BASE_URLMobile API base URL, default https://www.alza.cz
ALZA_VISITOR_IDOptional anonymous visitor UUID; otherwise generated per process
ALZA_OAUTH_AUTHORITYOAuth authority, default https://identity.alza.cz
ALZA_OAUTH_CLIENT_SECRETThe alza_Android OAuth client is confidential — token requests need its APK-embedded secret (default: the source-verified value; set "" to omit it for public clients). Used by auth_exchange and token refresh
ALZA_CLIENT_SECRETSame secret for the PKCE exchange scripts (scripts/e2e-order-payment.browser.mjs exchange, scripts/alza-auth-exchange.mjs)
ALZA_TOKEN_FILEJSON token store written by scripts/alza-auth-login* / scripts/alza_auth_login.py (default ~/.alza-mcp/tokens.json; set none to disable auto-load)

Plus:

  • 📦 Resource — alza://product/{code} lets agents read a product as a URI.
  • 💬 Prompt — /find-product is a guided shopping helper.
  • 🌍 Multi-locale — catalog locale configuration supports alza.cz, .sk, .hu, .at, .de, .co.uk via ALZA_BASE_URL; account/checkout verification is for CZ and some routes are fixed to the CZ host.

Configuration

All optional — alza-mcp works out of the box.

Env varDefaultPurpose
ALZA_BASE_URLhttps://www.alza.czSwitch locale: https://www.alza.cz, .sk, .hu, .at, .de, .co.uk
ALZA_CDP_URLunsetConnect to your already-running Chrome via CDP instead of launching a managed Chromium. Reuses the existing browser session; set ALZA_MCP_SKIP_INSTALL=1 separately to skip the installation-time download. Launch Chrome with --remote-debugging-port=9222 and set ALZA_CDP_URL=http://localhost:9222.
ALZA_HEADLESStrueSet false to show the browser used for scraping and API fallback; OAuth/MFA/payment interactions remain user-controlled
ALZA_IDLE_TTL_MS180000Close the headless Chromium after this many ms with no tool calls. Lower it on memory-constrained machines; raise it (or disable by setting absurdly high) if you make many calls in quick succession and don't want the relaunch latency.
ALZA_DEBUGfalseVerbose stderr logging

Running over HTTP (Streamable HTTP)

stdio is the default and what the install snippets above use. To serve the same server over MCP Streamable HTTP instead, for example for a client that only takes a URL:

bash
npx -y alza-mcp --http --port 3000          # or: ALZA_TRANSPORT=http ALZA_HTTP_PORT=3000 npx -y alza-mcp# → MCP endpoint http://127.0.0.1:3000/mcp, health check http://127.0.0.1:3000/healthz
claude mcp add --transport http alza http://127.0.0.1:3000/mcp

On HTTP the server is stricter than on stdio, because a network endpoint can be reached by more than one client:

  • Catalog only by default. Only the read-only, anonymous toolsets are usable: catalog (on) and pc_builder (enable with set_toolset). Every other toolset (auth, basket/checkout, account, orders/payments, reviews/subscriptions, chat, advanced_raw) is locked: list_toolsets shows it with the reason, and set_toolset refuses to enable it. These tools sign in to and act on a real Alza account (orders, payments, credentials), so a shared endpoint must not offer them by accident. Set ALZA_HTTP_ENABLE_ACCOUNT=1 to unlock them.
  • One server per MCP session. Each Mcp-Session-Id gets its own server instance: its own toolset state, OAuth tokens and one-time confirmation tokens. With ALZA_HTTP_ENABLE_ACCOUNT=1, each session also gets its own browser context and Chrome-fingerprint sidecar, because both keep Alza cookies. Sessions expire after 30 idle minutes.
  • No token file. ALZA_TOKEN_FILE (~/.alza-mcp/tokens.json) holds one person's login, so HTTP mode does not load it. Each session signs in with auth_start → auth_exchange. For a single-user localhost setup you can set ALZA_HTTP_ALLOW_TOKEN_FILE=1 (together with ALZA_HTTP_ENABLE_ACCOUNT=1); every session then starts signed in as that account, so never do this on a shared host. All sessions start from the same refresh token and Alza rotates it on refresh, so the first session that refreshes invalidates the copy the others hold (they then need auth_start → auth_exchange); keep to one active session in this mode.
  • Localhost only by default. It binds 127.0.0.1 and rejects requests whose Host or Origin is not a loopback name (DNS-rebinding protection). There is no built-in authentication or TLS. If you bind elsewhere (--host 0.0.0.0), put it behind a reverse proxy that does both, and set ALZA_HTTP_ALLOWED_HOSTS.
Env var / flagDefaultPurpose
--http, ALZA_TRANSPORT=httpstdioServe over Streamable HTTP
--port N, ALZA_HTTP_PORT (or PORT)3000Listen port (0 picks a free one)
--host H, ALZA_HTTP_HOST127.0.0.1Bind address
ALZA_HTTP_ALLOWED_HOSTSloopback names when bound to loopback, otherwise no checkComma-separated hostnames accepted in Host/Origin
ALZA_HTTP_ENABLE_ACCOUNToffUnlock the auth/account/checkout/order/payment toolsets (per-session logins)
ALZA_HTTP_ALLOW_TOKEN_FILEoffAlso load ALZA_TOKEN_FILE into every session (single-user only; needs ALZA_HTTP_ENABLE_ACCOUNT)
ALZA_HTTP_MAX_SESSIONS50Concurrent session cap (HTTP 503 beyond it)
ALZA_HTTP_SESSION_IDLE_MS1800000Close a session after this long without a request (a session holding an open GET/SSE stream is not closed)

Hosting is not supported yet. A hosted endpoint (Vercel mcp-handler, Fly, Railway, …) is a follow-up. The main obstacle is Cloudflare, not the transport: Alza is behind Cloudflare Bot Management, and both the headless browser and the curl_cffi sidecar get through it from a residential IP (live-verified) but are far more likely to be challenged from a datacenter IP. A hosted instance will probably need a residential proxy or a browser-as-a-service (for example Browserbase via ALZA_CDP_URL). The daily canary's GitHub-hosted runs show this: they get Cloudflare's interactive challenge. Other things a host needs: Chromium and Python with curl_cffi in the image, enough memory for one browser per account session, sticky routing (sessions live in one process's memory), and authentication in front of the endpoint. Keep the account toolsets locked on any multi-user host.


Pi agent integration

Register the local build in pi's global MCP config (~/.pi/agent/mcp.json):

json
{  "alza": {    "command": "node",    "args": ["/absolute/path/to/alza-mcp/dist/index.js"]  }}

Run /reload (or mcp connect alza — the gateway respawns the stdio process, so a freshly built dist/ takes effect without /reload). The gateway exposes the tools (55 domain tools plus list_toolsets/set_toolset; only the catalog and auth toolsets are enabled until you call set_toolset) under the alza_ prefix (alza_search_products, alza_get_product, alza_cart, …). Auth auto-loads from ~/.alza-mcp/tokens.json. Verified in both modes: (a) in-session through the gateway — search/filter/detail, authenticated add-to-cart, bogus-coupon round-trip → server-side err:1 envelope (docs/live-evidence/pi-integration-2026-09-10.md); and (b) headless (pi -p one-shot prompt), where the agent discovers the alza_* tools, calls search_products with the right args, and reports the correct cheapest in-stock product (docs/live-evidence/headless-pi-2026-09-12.json); the 2026-09-13 re-run adds three more headless scenarios — catalog search with price-ascending sort, the authenticated account stack (account_status + cart), and the one-time mutation token flow (prepare_mutation) — all captured in docs/live-evidence/headless-pi-2026-09-13.json.


How it works

Alza has no public consumer API. This project reverse-engineers the Android app's REST surface (route names and DTOs recovered from the APK) and the website's own checkout pipeline. Neither is a supported or documented interface, so any of it can change or break without notice.

Cloudflare Bot Management. Alza sits behind it and returns HTTP 403 to plain HTTP clients. This server gets past it in two ways: a headless Chromium (catalog scraping) and a Chrome-fingerprint HTTP sidecar (scripts/cf-transport.py, using curl_cffi to impersonate Chrome's TLS/HTTP2 fingerprint) for the account/checkout API. That is circumvention of a bot-protection measure, which Alza's terms of use may prohibit. The sidecar and its setup script ship in the npm package, and postinstall tries to set up its curl_cffi venv. It stays optional: without Python or curl_cffi, the account stack (including OAuth sign-in) falls back to plain fetch and, for same-origin API calls, the browser. See the Disclaimer and SECURITY.md before using it.

No generic arbitrary-route tool is exposed. What is and isn't covered:

  • Excluded: administrative login routes, telemetry/audit routes, device-token and anonymous-activity routes, and external payment hand-offs (Klarna, Google Pay) plus the quick-order payment family (documented as blocked in the coverage matrix).
  • Included, behind one-time tokens: order placement and cancellation, account registration, and credential/identity changes (password, 2FA, phone, email, account deletion — delete_account is irreversible).
  • Server-driven action URLs are followed only when returned by a confirmed response, through the origin-validated AppActionExecutor (GET/POST, path allowlist, sensitive-field blocklist, one-time confirmation token); they are not accepted as arbitrary MCP URLs.

The complete 12-family route inventory with method, DTO, prerequisites, side effects, exposure, and verification status is maintained in docs/mobile-endpoint-coverage.md.

Legacy catalog compatibility still uses the original page adapter:

  • Search navigates /search.htm?exps=... and scrapes .browsingitem cards.
  • Product detail comes from page JSON-LD.
  • Reviews use JSON-LD aggregate ratings.
  • Pickup points combine branch data and geocoding.
  • Per-process caching remains enabled.

Image, font, and analytics requests are blocked at the route level. Catalog pages still load scripts, and sorted searches may fetch multiple result pages. Typical latencies: search ~2 s, product detail ~5 s warm.

┌────────────────────────────────────────────┐│ stdio transport (npx alza-mcp)             │├────────────────────────────────────────────┤│ MCP tools / resources / prompts            ││  grouped into toolsets (toolsets.ts)       │├────────────────────────────────────────────┤│ Domain: catalog · reviews · pickup ·       ││         mobile-account (cart/checkout/…)   │├────────────────────────────────────────────┤│ Infra:                                     ││  • browser (Playwright, CDP)               ││  • impersonate-transport (curl_cffi        ││    Chrome-fingerprint sidecar)             ││  • mobile-api (APK-derived REST client)    ││  • jsonld (schema.org parser)              ││  • cache (LRU + TTL)                       ││  • locale (multi-country)                  │└────────────────────────────────────────────┘

For deeper architecture notes — including why we don't ship the HTTP/okhttp recipe — see ARCHITECTURE.md.


Development

bash
git clone https://github.com/lukabudik/alza-mcp.gitcd alza-mcpnpm install                 # auto-installs Chromium via postinstallnpm test                    # unit tests, no networknpm run typechecknpm run build               # → dist/npm run eval                # agent-driven MCP eval harness (6 scenarios) → docs/live-evidence/npm run validate:api        # hits real Alza — runs every tool end-to-endnpm run pentest:app-action  # Node AppAction transport comparisonnpm run live:endpoint-matrix # bounded read-only APK route matrix; requires ALZA_API_BASE_URLnpm run live:user-journeys   # catalog, delivery/cart, and anonymous-account journeysnpm run auth:login:py        # PKCE login step 1 (prints browser URL + pending-login.json)npm run auth:exchange        # PKCE login step 2 (Node, needs a CF-friendly egress)node scripts/e2e-order-payment.browser.mjs exchange "<pasted alza://identity redirect>"                             # step 2 via Playwright (works even when Cloudflare challenges plain HTTP)npm run live:e2e             # real order + after-order payment through the MCP tools                             # (browser-backed transport; use ALZA_HEADLESS=false to watch it)npm run live:e2e:node        # same journey over plain HTTP (in-memory MCP client); needs a                             # non-challenged egress or a fresh ~/.alza-mcp/tokens.jsonSTOP_BEFORE_ORDER=1 npm run live:e2e   # dry run: stop right before order submissionALLOW_ANON=1 STOP_BEFORE_ORDER=1 npm run live:e2e                             # anonymous dry run; ALLOW_ANON alone does not prevent orderingnode dist/index.js          # run the server (waits for stdio MCP messages)node dist/index.js --http   # or serve MCP Streamable HTTP on http://127.0.0.1:3000/mcp

Further reading:


Roadmap

main already covers catalog, filtering, cart, checkout, order placement/cancellation and account management (see What it does and the known limitations in docs/gap-analysis.md). Next up:

  • PC builder follow-ups (#15; pc_builder toolset shipped) and a hosted HTTP endpoint (follow-up to #16; local --http mode is shipped)

Priorities live in ROADMAP.md; everything is tracked in issues — good first issue is the place to start.


FAQ

Why the 92 MB Chromium download?

Alza's bot protection can challenge ordinary HTTP requests. The catalog uses headless Chromium to render product pages; the account stack can also use the optional Chrome-fingerprint sidecar, with browser-backed requests as a fallback. Chromium is installed by the postinstall hook or on first launch if needed. See How it works.

How are login and ordering protected?

  1. OAuth sign-in does not pass the Alza password as an MCP tool argument — sign-in happens in the user's browser (OAuth PKCE) and the MCP only exchanges the returned code. Tools that necessarily carry credentials as arguments (register, change_password, phone_change, email_change) require an explicit one-time token and should only be called with the user's direct instruction.
  2. checkout_preview creates a one-time confirmation token after the cart and delivery choice are reviewed; place_order refuses arbitrary tokens.
  3. web_place_order (the currently working submission path — mobile place_order returns HTTP 500 server-side) and every other high-impact mutation (cancel_order, pay_after_order, delete_account, …) require a one-time token from prepare_mutation. Tokens are single-use and bound to one action. MFA and 3-D Secure remain user-controlled browser interactions.
  4. These tools create, change and cancel real orders and accounts. The token is a guard against accidental calls by an agent, not a substitute for the user confirming the action — have your agent show the order summary and ask first.

Can I avoid the Chromium download?

Yes. Set ALZA_CDP_URL to your existing Chrome's debug port:

bash
# launch Chrome with debugging/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome \  --remote-debugging-port=9222# tell alza-mcp to attachALZA_MCP_SKIP_INSTALL=1 ALZA_CDP_URL=http://localhost:9222 npx alza-mcp

The MCP will use your Chrome — no separate download, faster cold starts, and it inherits any Alza cookies you already have.

Will Alza take this down?

It might, and you should assume that's possible. The project has no commercial intent, caches to minimize traffic, and provides a takedown contact path via issues — if Alza requests removal, we'll comply. But it does get past Alza's bot protection (see How it works), so it is not a polite scraper by Alza's standards, and Alza's terms of use may forbid it. Use it for personal automation, not at scale.

How does this compare to rohlik-mcp?

tomaspavlin/rohlik-mcp is the inspiration. Differences:

  • Rohlik isn't behind a Cloudflare challenge → rohlik-mcp uses plain HTTP. We're forced to a real browser because Alza is.
  • Alza is a much larger catalog (millions of SKUs vs. a grocery list).
  • We cover the whole purchase path (cart, checkout, order placement and cancellation) plus account management, not only catalog reads, and group the tools into toolsets so only the catalog and auth toolsets are enabled by default.
  • We expose MCP resources and prompts in addition to tools.

Disclaimer

alza-mcp is not affiliated with, endorsed by, or sponsored by Alza.cz a.s. "Alza", "Alza.cz", and "AlzaBox" are trademarks of their respective owners.

What this software does. It is a reverse-engineered client. Its mobile-API routes and data shapes were recovered from the Alza Android application, and its catalog tools scrape alza.cz pages with a headless browser. To reach Alza's servers it circumvents Cloudflare Bot Management (headless Chromium plus a Chrome-fingerprint HTTP sidecar). The Android app's OAuth client credential, which is embedded in the public APK, is used as the default for the token exchange.

Legal. None of this is a published or supported interface, and Alza's terms of use may prohibit automated access, bot-protection circumvention and reverse engineering. Whether and how you may use this software depends on your jurisdiction and your agreement with Alza. You are solely responsible for that determination. This is not legal advice, and the maintainers make no representation that use of this software is lawful or permitted.

It acts on real accounts and spends real money. The checkout, order, payment, registration and account-deletion tools operate on live Alza accounts. Orders placed are real and binding; cancellation is not guaranteed to succeed. One-time tokens guard against accidental agent calls but are not a substitute for confirming each action yourself. Test only with accounts and orders you are prepared to lose, and never with credentials you are not prepared to expose to your agent's context.

No warranty. Provided "as is" under the MIT license. The maintainers make no guarantees of availability, accuracy, or fitness for any purpose, and are not liable for orders, charges, account lockouts or bans resulting from its use. The upstream interfaces can change without notice, so any tool may stop working. Do not rely on this for commercial decisions.

Security issues — see SECURITY.md. Alza employees or rights holders with concerns: please open an issue or contact the maintainers — we will respond promptly and comply with reasonable removal requests.


License

MIT. See LICENSE.

Contributors

[图片]
Luka Budík

Creator, maintainer
[图片]
Samuel Seidel

Maintainer

A big thank you to Samuel Seidel, the project's first outside contributor and now a co-maintainer. He built the account, cart, checkout and order tools, toolsets, typed output schemas, category filtering and the live-verified test harness, which together took alza-mcp from a 5-tool catalog browser to a full shopping agent (#1, #5).

Contributions are welcome — see CONTRIBUTING.md and the open issues.

Acknowledgements

来源:README.md,提交 c6169f1

工具

0
工具元数据尚未被收录。

版本历史

1
  1. v0.4.0最新Oct 7, 2026