Skip to main content
Glama

English · Русский

Ozon MCP

An MCP server for one ozon.ru buyer account. It reads orders, purchases, returns, the cart, favorites, wishlists, «Подборки», product cards, catalog search, the Ozon Card balance and points — and, when explicitly allowed, changes the cart and the lists and runs an order: forming a checkout, placing it, paying, cancelling it item by item.

None of this has a public API. The server talks to the same internal composer-api / entrypoint-api endpoints the site's own frontend uses, under your authenticated session.

Requirements

  • A Russian IP. Ozon blocks datacenter and VPN egress.

  • A real Chromium. Headless is detected; the image runs it under Xvfb.

  • One interactive login, performed once against the profile directory.

  • --shm-size=1g. Chromium crashes on Docker's default 64 MB.

Related MCP server: marketplace-mcp

How it works

The Variti antibot blocks non-browser clients, but a browser only has to pass the challenge once. A real Chromium starts, passes it, and hands over its cookies and the exact client-hint header set; from then on every read and write is a direct HTTP call through curl_cffi with Chrome's TLS fingerprint. No tool renders a page, which is why a call takes about 0.2 s instead of 15. The browser stays only to own the profile, refresh the session, and serve as the fallback for one reading — the delivery estimate.

The session lives in a persistent Chromium profile, not a cookie snapshot. OzonID, the auth realm guarding checkout, keeps its state outside cookies and localStorage, so a Playwright storage_state snapshot silently loses it and checkout falls back to a login prompt. A profile directory keeps everything, so one login stays valid and the server runs unattended.

Playwright's sync API cannot run inside a live event loop, and its objects belong to the thread that created them, so tool calls are dispatched to a single worker thread. They are therefore serialised, and a slow one — a bootstrap, a login — makes the others wait.

Tools

Orders and returns

Tool

list_orders

Orders (active / archive / all), each with its order_number, status, state, pickup point, slot, what is owed on collection and per-item payment state; optionally within an ISO date range

order_products

Items of one order: sku, title, price paid, variant, seller, and each item's parcel status

purchases

Everything ever ordered, as product tiles; with a query, Ozon's own search over the whole history

bought_items

What was actually received: the purchase list matched against the orders, with the coverage of the scan

list_returns

Returns: number, date, status, amount, the products going back

Catalog

Tool

search

Storefront search by text and/or category slug, with sort, facet filters and a depth limit

get_search_filters

Facets available for a query, and the values search takes

product_details

Card: price, variants (each with its own sku), characteristics, photos; description and reviews on request

get_reviews

Rating, review count, the breakdown per star, and reviews to any depth (sort="worst" for the complaints)

get_description

Description text plus the images embedded in it

delivery_estimate

When a product would arrive, to which address, from which warehouse

find_cheaper

The cheapest lots of the same thing: Ozon's own other-seller offers plus a price-sorted search

Cart

Tool

get_cart

The whole cart: items, quantities, ticks, group headings, and the size Ozon declares

set_cart_quantity

Set the quantity; 0 removes

select_cart_items

Tick what makes up the order — only / add / remove / all / none

Favorites and wishlists

Tool

list_favorites

Favorites as product tiles

set_favorite

Add or remove

get_lists

Wishlists with their ids and sizes; with a sku, whether each holds it

create_list / delete_list

Make a wishlist, or delete one

set_list_membership

Put a product in a wishlist or take it out

check_favorite_price_drops

Price changes since the previous call

«Подборки»

Tool

list_selections

Selections with size, status, ids and the share link

get_selection

One selection in full, including description and visibility

selection_products

What it holds: sku, title, price, card link

create_selection

Create one around a product; private by default

add_to_selection

Add products, keeping the ones already in it

remove_from_selection

Take products out, keeping the rest

set_selection_items

Replace the whole list of products

edit_selection

Rename it, replace its description

set_selection_public

Publish to the public profile, or unpublish

delete_selection

Delete it; the products stay

Checkout

Tool

get_checkout

The order being formed: payment methods, pay-on-delivery, destinations, pickup points, shipments, points, totals

configure_checkout

Set payment, points, pay-on-delivery and pickup point in one call

place_order

Spends money. Submit, waiting until the order exists

pay_order

Charge an order left unpaid, and report what is left to do

list_cancel_reasons

Reasons Ozon accepts for cancelling

cancel_order

Cancel an order, or named items of it, returning them to the cart

Session and money

Tool

session_status

Whether the session acts as the account, and which gates are open

start_login / submit_login_code

Restore a dead session with a one-time code

get_finances

Ozon Card balance and total points

get_points

Points by type, burning points, per-store seller bonuses

Changing the account is off by default. OZON_ENABLE_WRITES=1 allows the cart, favorites, lists and cancellations; OZON_ENABLE_ORDERS=1 allows place_order and is separate because it spends money. session_status reports both, so a caller can plan around them instead of finding out halfway through.

What a caller needs to know

Some of Ozon's behaviour does not follow from a tool's name.

The cart ticks are the order. get_checkout reports nothing orderable until something is ticked, and it orders exactly what is ticked — so "buy these two" is select_cart_items(skus, mode="only"), whatever else the cart holds. Ozon's checkout is a snapshot of those ticks taken when checkout is entered, and only an entry replaces it: unticking an item afterwards changes the cart and not the order. get_checkout and place_order therefore enter checkout before reading, which keeps the options already chosen.

Two money figures, never interchangeable. totals.total is what Ozon charges today; totals.order_total is what the order costs. On a pay-on-delivery order today's charge is 0 ₽, so order_total is the figure to quote to a person.

An order row has no total. Ozon prints none on the order list, so a row carries amount_due_at_pickup («К оплате при получении») and, per item, that item's price and paid. The sum owed on collection is not any item's price, and paid is null when Ozon says nothing — which is not unpaid.

«Текущие заказы» is not a list of current orders. Ozon keeps the recently received and cancelled ones on that page. scope="active" leaves them out; state says which of the three a row is.

Pay-on-delivery is not all-or-nothing. Ozon defers payment per shipment, so an order can be part deferred and part prepaid — an imported item usually has to be paid up front. pay_after_receipt.scope is full, partial or none; on a partial order pay_now_items and pay_on_receipt_items name the lines on each side, as Ozon splits them.

«Купленные товары» is a list of products, not of outcomes. It holds everything ever ordered — including what was refused at the pickup point — and states no order, no date and no status; its price is today's catalogue price, not what was paid. On the account this was built against, 17 of 29 items matching one query had been ordered and never taken home. The outcome lives in the orders: an order is delivered in parcels with separate fates, so order_products reports shipment_status and received per item, and bought_items matches the list against the orders to fill them in, and its answer states how far it looked: each order costs a request, so a bounded scan is partial and says so — unresolved is "never seen in the orders scanned", provisional is "seen only as cancelled, an older order may have been received".

An order's dates are status dates. The archive prints only «Получен 11 августа» / «Отменён 12 февраля 2021», so a date range filters on when an order was received or cancelled — an order placed on 30 June and received on 2 July lands in July. The archive is a newest-first cursor, so a window is walked down to: the cost is the depth, not the width. A recent fortnight comes back in half a second; a month two years back takes tens of seconds.

A rating is a number Ozon states. product_details carries rating, reviews_count and questions_count; get_reviews adds the per-star breakdown and walks pages to the depth asked for, reporting count (the product's total) beside fetched (what came back) — they are different numbers. Ozon offers no filter by star, so the one-star reviews are reached with sort="worst" and depth. A card's reviews cover its variants, so each review names the size or colour it is about, and «Достоинства» / «Недостатки» stay apart from the comment.

Three prices, and only one of them is charged. A card states price («С банками» — what the account pays), price_regular («С другими банками») and price_old (struck through). Comparing lots on anything but the first calls a lot cheaper than it is, so search(sort="cheap") and find_cheaper rank on it.

Ozon's text search is literal. A lot whose own title omits the brand is not returned for a query that includes it — and when nothing matches exactly Ozon fills the page with "you might also like", which is dropped rather than passed off as results. So search the model, not brand-plus-model, and confirm what a lot is with product_details: a tile's title is the seller's wording and may name no model at all. limit is depth — pages are walked until it is met, because the cheapest lot is regularly not on the first one.

Wishlists and «Подборки» are different things. A wishlist has a numeric id and holds anything. A selection has a uuid, a cover, a description and a visibility; its products come from favorites only, and publishing puts it on the account owner's public profile after review. Its products are a separate read — the list states a count — and Ozon has no "add" of its own: the form submits the whole list, which is what add_to_selection / remove_from_selection do around the current contents.

Cancelling works line by line. cancel_order(order, skus=[...]) drops those items and leaves the rest of the order standing, in as many passes as it has items.

A card charge finishes on Ozon's bank domain, which signs the account in to the bank. pay_order drives the payment to that point and reports what remains: the amount, how much to top the card up by, and the page to finish at. Pay-on-delivery avoids the whole thing.

Errors carry a code as well as a sentence — [rate_limited], [session_expired], [writes_disabled], [orders_disabled], [total_mismatch], [upstream_unavailable]. Branch on the code; the sentence is written to be relayed to a person. A failure never arrives as an empty result: a 502 or a timeout raises, because "no orders" and "Ozon did not answer" are different answers.

Configuration

Variable

Default

OZON_PROFILE_DIR

/data/profile

Persistent Chromium profile holding the session

OZON_PROFILE_BACKUP

/data/profile.backup

Copy of a known-good profile, restored on a sign-out

OZON_STATE_PATH

/data/state.json

Legacy cookie snapshot, imported once to seed a new profile

OZON_IMPERSONATE

chrome124

curl_cffi TLS-impersonation profile

OZON_ENABLE_WRITES

0

Allow cart / favorites / list / cancellation changes

OZON_ENABLE_ORDERS

0

Allow place_order — spends money

OZON_MONITOR_STORE

/data/price_history.json

Favorites price-history file

OZON_REQUEST_TIMEOUT

30

Seconds for one HTTP call

OZON_REQUEST_ATTEMPTS

3

Attempts before a call is reported as failed

OZON_RETRY_BACKOFF_SECONDS

1

Base wait between attempts, doubled and jittered

OZON_RETRY_CAP_SECONDS

20

Longest wait, including a Retry-After Ozon asks for

OZON_BROWSER_TIMEOUT

60

Seconds for a browser navigation or a login step

OZON_IDLE_SECONDS

600

Close the idle browser; the HTTP session stays

OZON_TRANSPORT

stdio

stdio (client spawns the process), http (streamable HTTP at /mcp) or sse (deprecated, /sse)

OZON_HOST / OZON_PORT

0.0.0.0 / 8084

Bind for the HTTP transports; the same port serves /metrics

OZON_ALLOWED_HOSTS

[]

Host headers the HTTP transports (http and sse) accept; empty means any. Naming hosts turns on MCP's exact-match check

See env.example.

Running

docker build -t ozon-mcp .

# stdio: the client attaches to the container's stdin/stdout
docker run -i --rm --shm-size=1g -v /opt/ozon-mcp:/data ozon-mcp

# http: long-lived service on :8084 (/mcp + /metrics)
docker run -d --name ozon-mcp --shm-size=1g -v /opt/ozon-mcp:/data \
  -e OZON_TRANSPORT=http -p 8084:8084 ozon-mcp

/data has to be a bind mount. It holds the profile, and Ozon rotates the session constantly: cookies rotated over HTTP are pushed back into the profile so the refresh chain survives a restart. On an ephemeral directory the login is lost on every container recreation.

The profile is a credential. It grants full access to the account — orders, addresses, card balance, checkout. Never commit it; back it up encrypted.

Locally, with uv:

uv sync
uv run playwright install --with-deps chromium
uv run python -m ozon_mcp   # needs a display or Xvfb

Under http and sse the same port serves Prometheus metrics at /metrics: upstream request outcomes and latency, antibot re-challenges, session bootstraps, browser state.

Session lifetime

A signed-out session looks exactly like an empty account — no orders, no balances, no explanation — so every tool raises instead of answering, session_status reports the state, and start_login / submit_login_code restore it with a one-time code that only the account owner receives.

A profile known to be signed in is copied, and a sign-out is recovered from that copy automatically, so in most cases nobody is asked for a code.

Several agents at once

Multiple clients can connect over the HTTP transports, and each gets its own MCP session. They share one Ozon account and one worker thread, which has two consequences.

Calls are serialised: a second agent waits out the first, including a 13-second browser bootstrap.

More importantly, the account state is shared. Cart ticks live on Ozon's side, not in the MCP session, so two agents composing orders at once overwrite each other's selection — and place_order buys whatever is ticked at that moment, at a total the caller read a second earlier. Reads are safe for any number of agents; writes are not. Keep one writer per account.

The endpoint has no authentication: whoever reaches the port has the account.

Limitations

  • Only saved addresses can be chosen. configure_checkout switches between the points in the account's address book; adding one from the map is not implemented.

  • A selection's cover cannot be uploaded; that is a multipart upload and is not covered.

  • Per-shipment destinations are handled but unverified against a live order Ozon actually split across addresses.

  • pay_order cannot complete a card charge: that happens on Ozon's bank domain and needs banking credentials this server does not hold.

  • Placing an order spends real money, and is gated separately from every other write.

Development

make check-all   # ruff format --check, ruff check, ty, pytest with a coverage gate

ty runs with all = "error", ruff with select = ["ALL"] and a curated ignore list. Tests mirror src/; the service layer is driven through a stand-in for get_session() and the transport through a stand-in for the HTTP session, so nothing in the suite touches the network.

Disclaimer

Scraping a personal account is against Ozon's Terms of Service. This project is for personal, low-volume use, and you are responsible for how you use it.

License

MIT

Available Tools

42 tools
add_to_selectionA

[GATED by writes_enabled] Add products to a «Подборка», keeping what is already in it. Products must be in favorites first — Ozon draws only from there and drops the rest silently, so check the items count that comes back.

Inputs: skus (required), uuid (required). Returns: One «Подборка» — a curated list of products, publishable to a profile. A differ…

cancel_orderA

[GATED by writes_enabled] Cancel an order, by default returning its items to the cart. skus cancels only those lines and leaves the rest of the order standing — an order can be cancelled item by item, in as many passes as it has items. Omit it to cancel the whole order. The selection is checked against what Ozon reports back and refused on a mismatch, since cancelling the wrong line is not undoable. reason_id from list_cancel_reasons; "504" (изменить заказ и оформить заново) is the neutral default, "508" needs a comment. Check cancelled in the result — Ozon may answer with a retention offer instead, and detail then carries what it asked.

Inputs: order (required), skus, comment, reason_id, +1 more. Returns: Result of a cancellation, with what Ozon reported back. ``skus`` is empty when…

check_favorite_price_dropsA

Record the current favorites prices and return the diff against the last run: {drops, rises, added, removed}. Call it periodically — the comparison is only as old as the previous call.

Inputs: no named parameters. Returns: added, drops, rises, removed

configure_checkoutA

Set checkout options and return the recomputed order — one call can set several. Omit an argument to leave that option alone. Every value comes from a get_checkout() answer, so read that first; passing something Ozon does not offer is refused with the list of what it does. Applied in the order Ozon recalculates them: destination, payment, pay-on-delivery, points. Turning points on can withdraw the pay-on-delivery offer, so check the result rather than assuming.

Inputs: points, payment, split_key, pickup_point, +1 more. Returns: The whole checkout state, read-only. ``pay_after_receipt`` is a switch, not a p…

create_listA

[GATED by writes_enabled] Create an empty wishlist and return it with its list_id, ready for set_list_membership(). An empty name is refused by Ozon. Wishlists are the only list this account can create — «Подборки» are not made this way.

Inputs: name (required). Returns: A collection (подборка) or wishlist (вишлист). ``list_id`` is what ``set_list_m…

create_selectionA

[GATED by writes_enabled] Create a «Подборка» around one product and return it with its uuid. More products go in with add_to_selection(). public defaults to false on purpose: publishing puts it on the account owner's public profile, so ask them before passing true.

Inputs: sku (required), name (required), public, description. Returns: One «Подборка» — a curated list of products, publishable to a profile. A differ…

delete_listA

[GATED by writes_enabled] Delete a wishlist. The products in it are not deleted — they stay in favorites and in any other list. Not undoable: the list itself is gone, so confirm with the user first.

Inputs: list_id (required). Returns: The outcome of a change to the account. Ozon answers a mutation with a page fra…

delete_selectionA

[GATED by writes_enabled] Delete a «Подборка». The products in it are not deleted. Ozon's own warning: «Восстановить её не получится» — so confirm with the user first.

Inputs: uuid (required). Returns: The outcome of a change to the account. Ozon answers a mutation with a page fra…

delivery_estimateA

When a product would arrive, to which of the account's addresses, and from which warehouse ("Завтра, 2 сентября" / "ул. Данилова, 17" / "Со склада Ozon"). The date is relative to that address, so quote both. This is per product, before ordering; for an existing order the dates are in list_orders(), and for an order being formed in get_checkout().

Inputs: sku_or_url (required). Returns: When a product would arrive, and what that estimate is relative to. The date me…

edit_selectionA

[GATED by writes_enabled] Rename a selection, and optionally replace its description. Visibility is preserved: an edit carries it, so a public selection stays public and a private one stays private.

Inputs: name (required), uuid (required), description. Returns: One «Подборка» — a curated list of products, publishable to a profile. A differ…

find_cheaperA

The cheapest lots of the same thing, ranked by payable price — top limit (default 10). Looks in both places Ozon keeps them: its own «Есть дешевле или быстрее» offers for this exact product, and a price-sorted search by the card's title, which reaches the same product listed separately. Entries carry seller and delivery when they came from the offers list, and offers have no title — confirm the model with product_details() before quoting one. Raises when the base price cannot be read, rather than answering "nothing is cheaper" for a product it failed to price.

Inputs: sku_or_url (required), limit. Returns: base, cheaper

get_cartA

The whole cart (paginated through): items with title, price, quantity and checked — the tick is what decides the order's contents — plus Ozon's own group headings ("Доступны для заказа", «Бронирование товаров»).

Inputs: no named parameters. Returns: The whole cart, paginated through. ``groups`` are Ozon's own headings ("Доступн…

get_checkoutA

The order being formed from the selected cart items, with everything that can be changed: payment methods (each with its payment_type), the pay-on-delivery switch, one entry per destination in deliveries (each with its shipments in split_keys and its selectable pickup_points), the shipments with their delivery dates, points choices and the money breakdown — totals.total is what Ozon charges today (0 ₽ on a fully deferred order) and totals.order_total is what the order costs.

Pay-on-delivery does not always cover the whole order. pay_after_receipt .scope is one of "full", "partial" (some items must be paid up front: prepayment_amount now, post_payment_amount on receipt) or "none", and .note states it in words. On a partial order pay_now_items and pay_on_receipt_items name the lines on each side, as Ozon itself splits them, and the shipments are loaded with their items, each carrying prepaid (null when it holds items from both sides). shipment_items forces that loading on (true) or off (false); by default it happens only when scope is "partial".

Forms the checkout itself if Ozon has not yet. If it reports available=false, reason says what to fix — usually: select cart items. Change it with configure_checkout, submit with place_order.

Inputs: shipment_items. Returns: The whole checkout state, read-only. ``pay_after_receipt`` is a switch, not a p…

get_descriptionB

Product description text plus the images embedded in it.

Inputs: sku_or_url (required). Returns: sku, images, description

get_financesA

Ozon Card balance and the total points. This balance is what a card payment draws on, so it is what decides whether pay_order() will need a top-up. Breakdown by point type → get_points().

Inputs: no named parameters. Returns: points, ozon_card_balance

get_listsA

The account's wishlists (вишлисты), each with its size and list_id — which is what set_list_membership() and delete_list() take. With a sku, every list also carries contains, so a product already in a list is not added twice. Ozon's «Подборки» are a different thing, kept elsewhere and not exposed.

Inputs: sku. Returns: result

get_pointsB

Points by type (Ozon points, miles, WOW points, stars) with amounts, burning points, and per-store seller bonuses.

Inputs: no named parameters. Returns: burning, by_type, seller_bonuses

get_reviewsC

Reviews on their own: overall score, individual reviews (author/score/text/date) and review photos.

Inputs: sku_or_url (required). Returns: count, score, photos, reviews

get_search_filtersA

Facets available for a query: {name, key, type, options|range}. Apply them with search(filters={key: value}) — checkbox/category value = option.value, range value = "min;max". Flow: search → get_search_filters → search(filters).

Inputs: query (required). Returns: result

get_selectionA

One «Подборка» in full: name, description, product count, status and public — whether it is published to the account's public profile. list_selections() does not carry the description or public; this does, and it is the only reliable read of visibility, because a selection under review is listed as "На модерации" either way.

Inputs: uuid (required). Returns: One «Подборка» — a curated list of products, publishable to a profile. A differ…

list_cancel_reasonsA

Reasons Ozon will accept for cancelling an order, with their reason_id. The catch-all one (needs_comment=true) is refused without a comment.

Inputs: order (required). Returns: result

list_favoritesA

Favorites as product tiles: sku, title, price, old price, url. Paginated through for you — limit caps how many come back, there is no page to ask for.

Inputs: limit. Returns: result

list_ordersA

Orders with status, state (active/received/cancelled), pickup point, delivery slot/ETA and their items. No order total: Ozon states none on the list. Money is amount_due_at_pickup («К оплате при получении», what is owed on collection) per entry, and price plus paid true/false per item. An item's price is not the order's; paid null means unknown, not unpaid. An entry is a delivery group: items arriving together share it, so order_numbers can hold several and its items can be paid and unpaid. Giving either date searches the archive and stops paginating once past the window — cheaper than pulling the whole history for one month. Pass an entry's order number or detail_link on to order_products(), cancel_order() or pay_order().

Inputs: limit, scope, date_to, date_from. Returns: result

list_returnsA

Returns this account has opened, newest first: the return number, the date of the application, Ozon's own status badge ("Деньги отправлены", "Ждём товар") and the sentence under it, the amount, and the products going back. Paginated through — limit caps how many come back.

Inputs: limit. Returns: result

list_selectionsA

The account's «Подборки» — curated, publishable lists of products, a different thing from the wishlists in get_lists(). Each carries the uuid every other selection tool takes, how many products it holds, and Ozon's own status: "Личная подборка" while private, "N сохранений" once public, "На модерации" while a publication is being reviewed.

Inputs: no named parameters. Returns: result

order_productsB

Items of one order: sku, title, price paid, chosen variant, seller and a product-card link. Accepts an order number ("44563249-0865") or a detail_link from list_orders()[].detail_link.

Inputs: order (required). Returns: result

pay_orderA

[GATED] Ask Ozon to charge an order left in «Ожидаем оплаты», and report what the user must still do. The result spells it out: amount_due is the charge, shortfall is set when the Ozon Card balance does not cover it (top up by that much), and next_step is the instruction to relay. payment_url is where the payment is completed — that page signs the account in to Ozon Bank, which is the owner's step, so this server never finishes the charge itself. Tell the user plainly: top up by shortfall if present, then finish at payment_url. Ordering with pay-on-delivery avoids all of it.

Inputs: order (required). Returns: Where a card payment stands after asking Ozon to charge it. The charge runs on…

place_orderA

[GATED by orders_enabled — SPENDS REAL MONEY] Submit the order that get_checkout() describes. Not undoable from here except by cancel_order(). Read get_checkout() immediately before, show the user totals.order_total — what the order costs — and pass back the figure they agreed to. The call is refused if that no longer matches, and nothing is ordered. Returns once the order actually exists, with its order_number: keep it, it is what cancel_order() and pay_order() need. Paying from the Ozon Card balance settles with the order; pay-on-delivery leaves nothing to pay today.

Inputs: confirm_total (required). Returns: Result of a submitted order, once Ozon has actually created it. Paying from the…

product_detailsA

Product card: title, three prices, variants, characteristics, gallery photos. Money as Ozon prints it: price is «С банками» — what the account actually pays and the figure to compare lots on — price_regular is «С другими банками», price_old the struck-through comparison. available says whether it is on sale at all. cheaper_offers / cheaper_from are Ozon's own count and lowest price for other offers of this product; find_cheaper() lists them. Each variant carries its own sku, price and availability — that sku is what goes into the cart, and for apparel it is the only one that will add. with_description / with_reviews fetch those too (separate requests each); get_description() and get_reviews() do the same on their own.

Inputs: sku_or_url (required), with_reviews, with_description. Returns: Everything on a product card. ``description`` and ``reviews`` come from separat…

purchasesA

Everything ever bought, as product tiles (sku/title/price/url) — the answer to "have I bought this before" and "buy that thing again". With query Ozon searches its own purchase history server-side, which is much cheaper than paging through all of it. Orders, statuses and totals are not here: that is list_orders().

Inputs: sort, limit, query. Returns: result

remove_from_selectionA

[GATED by writes_enabled] Take products out of a «Подборка», keeping the rest. Fails if the selection holds none of them, rather than reporting a removal that did not happen.

Inputs: skus (required), uuid (required). Returns: One «Подборка» — a curated list of products, publishable to a profile. A differ…

select_cart_itemsA

[GATED by writes_enabled] Choose which cart items make up the order. This is the step that composes a checkout: get_checkout() reports nothing orderable until something is ticked, and it orders exactly what is ticked — so "buy these two" is mode="only" with those two skus, whatever else the cart holds. Returns the cart as it is afterwards, so the ticks can be checked before ordering.

Inputs: mode, skus. Returns: The whole cart, paginated through. ``groups`` are Ozon's own headings ("Доступн…

selection_productsA

The products a «Подборка» holds: sku, title, price and a card link. Neither list_selections() nor get_selection() carries them — they state a count only — so this is the read to make before changing what is in there.

Inputs: uuid (required). Returns: result

session_statusA

Start here. Reports whether the stored session still acts as the account and what this server is allowed to do: writes_enabled covers cart, favorites and lists, orders_enabled covers placing an order. Both are the operator's settings and no tool can change them — plan around them. When signed_in is false, every other tool raises instead of answering, because a signed-out session otherwise looks exactly like an empty account: no orders, no balances, no explanation. Recovery is start_login() + submit_login_code(), and backup_available=true means it will most likely recover by itself on the next call.

Inputs: no named parameters. Returns: Whether the stored session can still act as the account, and what for. ``backup…

set_cart_quantityA

[GATED by writes_enabled] Set how many of a product are in the cart. Adding, changing and removing are all this one call: quantity=0 removes. Ozon reports nothing about the outcome, so the cart is read back: ok=false with the reason in detail means the call was accepted and changed nothing — an out-of-stock product, or an apparel base SKU with no size chosen (use the variant sku from product_details()). Being in the cart is not being in the order: tick it with select_cart_items() before checkout.

Inputs: sku (required), quantity (required). Returns: The outcome of a change to the account. Ozon answers a mutation with a page fra…

set_favoriteA

[GATED by writes_enabled] Add a product to favorites or remove it. Ozon reports no outcome for this, so detail names the read that confirms it — list_favorites(). Favorites are what check_favorite_price_drops() watches.

Inputs: sku (required), add. Returns: The outcome of a change to the account. Ozon answers a mutation with a page fra…

set_list_membershipA

[GATED by writes_enabled] Put a product into a collection or wishlist, or take it out. Ozon reports no outcome for this, so detail names the read that confirms it — get_lists(sku).

Inputs: sku (required), list_id (required), add. Returns: The outcome of a change to the account. Ozon answers a mutation with a page fra…

set_selection_itemsA

[GATED by writes_enabled] Set which products a selection holds, as the whole list. For "add this" / "take that out" use add_to_selection() and remove_from_selection(), which read the current products first; this one replaces them, and an empty list empties the selection. Products must be in favorites first — Ozon draws only from there, and a product that is not is dropped silently, so check the items count that comes back.

Inputs: skus (required), uuid (required). Returns: One «Подборка» — a curated list of products, publishable to a profile. A differ…

set_selection_publicA

[GATED by writes_enabled] Publish a selection to the account owner's public profile, or unpublish it. Outward-facing — confirm with them before publishing. Publication is reviewed by Ozon, so the status comes back as "На модерации" rather than public.

Inputs: uuid (required), public (required). Returns: One «Подборка» — a curated list of products, publishable to a profile. A differ…

start_loginA

Ask Ozon to send a one-time login code to login (account email or phone). Use this when session_status() reports signed_in=false and the kept profile copy did not recover it. Ozon delivers the code out of band (email, SMS or a flash call), so ask the user for it and pass it to submit_login_code().

Inputs: login (required). Returns: Where an interactive login has got to. Ozon sends a one-time code out of band,…

submit_login_codeA

Finish the login with the code Ozon sent, and keep a copy of the restored profile so the next sign-out costs nobody a code. Codes expire and are single-use: if it is refused, call start_login() again.

Inputs: code (required). Returns: Whether the stored session can still act as the account, and what for. ``backup…

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A3.6/5.0

    Scored across 42 tools

    Disambiguation4/5

    Each tool targets a distinct resource or action, and the descriptions carefully separate cart operations, search, checkout, orders, favorites, wishlists, selections, and auth. A few near-boundary cases like get_lists vs list_selections and product_details vs get_reviews/get_description are only disambiguated by reading the descriptions rather than the names.

    Naming Consistency3/5

    Most tools follow a get_/list_/set_/create_/delete_ verb-object pattern, but the set mixes standalone nouns like purchases, session_status, and selection_products with noun phrases like product_details and delivery_estimate. The inconsistency is not chaotic, but it is noticeable across 42 tools.

    Tool Count2/5

    42 tools is well beyond the 25+ threshold and makes the server feel heavy even for a broad e-commerce account domain. The surface is highly granular, with 10 selection tools and separate get_reviews/get_description calls that could plausibly be consolidated.

    Completeness4/5

    The core shopping lifecycle is well covered: search, product details, cart, checkout, payment, ordering, cancellation, favorites, wishlists, selections, purchases, and returns listing. The main gap is that returns can only be listed, not opened or managed, and there is no address management.

    Maintenance

    ActivitySlowing
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      D
      maintenance
      Connects AI assistants to Wildberries and Ozon seller accounts for real-time access to sales, stocks, prices, finances, and reviews through official APIs.
      MIT
    • A
      license
      A
      quality
      C
      maintenance
      Enables AI agents to read and work with Wildberries, Ozon, and Yandex Market seller accounts through typed tools, multi-account support, unified data schemas, rate limiting, audit, and encrypted credential storage.
      17
      65 npm
      MIT
    • A
      license
      A
      quality
      C
      maintenance
      Enables read-only analytics and product search for a Wildberries seller account, covering items, advertising, sales, stock, reviews, finances, and tariffs through MCP clients like ChatGPT or Cursor.
      12
      MIT
    • A
      license
      A
      quality
      B
      maintenance
      Ozon Seller API in your AI assistant: products, FBS and FBO orders, prices, stocks, finance and reviews. 441 methods live in a YAML catalog the server executes, the agent searches it in plain language and calls a method through three generic tools, and every method carries an access class so writes and irreversible calls ask for confirmation.
      25
      58 PyPI
      3
      MIT