MCP server for the Yango Tech Retail (grocery platform) B2B API — orders, receipts, products, prices, discounts, stocks and stores for AI agents.
Strong schema definitions and comprehensive parameter documentation. Tool names follow verb_noun conventions well. Descriptions are detailed and domain-specific, though some are verbose (exceeding 200 chars). All 16 tools have explicit input schemas with proper types and descriptions. Error handling guidance is present but could be more actionable. Security and composition are well-addressed. Main gaps: (1) output schemas are described in prose rather than formal JSON Schema; (2) some descriptions are overly long and could benefit from trimming to 50-200 char range for LLM optimization; (3) a few tools lack explicit actionability in error recovery; (4) tool annotations (readOnlyHint, destructiveHint) are present in the feature list but not verified in source code.
Cancels an existing order (POST /b2b/v1/orders/cancel). Optionally pass a reason. The response body is not documented upstream and is returned verbatim; verify the outcome with get_orders_state (expect canceled or pending_cancel).
Creates per-store product discounts (POST /b2b/v1/discounts/create), at most 100 per request. CAUTION: the exact key names inside discount_activity_period and discount_value are NOT documented (the official client types them as plain string→string maps with no example) — confirm the expected keys with Yango Tech before relying on this tool, and note there is no endpoint to list or delete discounts. The response body is not documented upstream (2xx = success) and is returned verbatim.
Creates an order on the Yango Tech platform (POST /b2b/v1/orders/create). You supply the order_id; the same body shape is used by the platform for order updates. All money fields are decimal STRINGS (e.g. "150.00"), never numbers. The response body is not documented upstream and is returned verbatim. After creation, track progress with get_orders_state (get_order does NOT return the state).
Creates (or upserts) products in the catalog (POST /b2b/v1/products/create), at most 100 per request. Each product uses the same shape query_products returns: {product_id, master_category, status, is_meta, custom_attributes}. custom_attributes must include longName ({lang: text}), shortNameLoc, markCount and markCountUnitList; extra keys are passed through. The response body is not documented upstream (2xx = success) and is returned verbatim.
Output schemas described in prose rather than formal JSON Schema. LLMs cannot parse prose-only output documentation; formal schemas enable downstream tool chaining and field extraction.
Some descriptions exceed 200 characters and include low-level API details (e.g., 'POST /b2b/v1/products/query', 'no parameters') that belong in implementation docs, not LLM-facing descriptions. This dilutes signal for the model's tool selection reasoning.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | B | 73 | 2026-07-28+ | v2 |
Details of a single order (POST /b2b/v1/orders/get): every field the order was created with (cart, delivery_address, payment_type, store_id, …) plus create_time. NOTE: the response does NOT include the order state — use get_orders_state for tracking.
Batch order tracking (POST /b2b/v1/orders/state). Returns {query_results: [{order_id, query_result, state?}]} — query_result reports per-order lookup success (an unknown id is reported here, not as an HTTP error). Known states: draft, checked_out, reserving, reserved, postpone_reserving, postponed, assembling, assembled, courier_assigned, delivering, closed, pending_cancel, canceled (the list is open-ended).
Product prices for one or more price lists (POST /b2b/v1/prices/get). Returns {results: [{pricelist_id, prices_data: [{product_id, price, price_per_quantity?}]}]}. price may arrive as a number or a string — treat it as a decimal either way.
Fiscal receipt(s) by receipt id OR order id (POST /b2b/v1/receipts/get) — pass exactly one of the two. Returns {receipts: [{receipt_id, order, create_time, store, receipt_type (payment|refund), payment_methods, items, client?}]}; items is a map keyed by item id, and all amounts are decimal strings. Client PII (full_name, phone_number, email, delivery_address) is included only for the fields you list in client_fields.
All stores (darkstores) of the retailer (POST /b2b/v1/stores/get, no parameters). Returns {stores: [{id, status, location: {lat, lon}, address?, name?]}. The store id is the WMS store id used by create_order, update_stocks and create_discounts; status values are not enumerated upstream.
Cursor-based order event feed (POST /b2b/v1/orders/events/query): new orders, state changes and issued receipts. Returns {cursor, orders_events: [{order_id, occurred, data: {type, …}}]} where data.type is state_change (with current_state), new_order, or receipt_issued (with receipt_id). Omit cursor for the first call, then keep passing the returned cursor — the feed is continuous, so poll again later with the last cursor.
Cursor-based price-list feed (POST /b2b/v1/pricelists/query) — the API's only way to list price lists, so a full snapshot means iterating until a page has fewer items than limit. Returns {pricelists: [{id, name, status (active|removed)], cursor}. Price-list ids feed get_prices and set_prices. Related endpoints without a dedicated tool (pricelists/get, pricelists/create, store-pricelist-links/*) are reachable via raw_request.
Cursor-based product catalog / product-updates feed (POST /b2b/v1/products/query). Returns {products, cursor}; iterate until a page has fewer items than limit to build a full snapshot. Each product: {product_id, master_category, status (active|disabled|archived), is_meta, custom_attributes}. custom_attributes carries localized maps (longName, shortNameLoc, descriptionLoc: {lang: text}), markCount + markCountUnitList (unit/gram/kilogram/liter/millilitre — open-ended), barcode[], images[], typeAccounting (byUnit|byWeight|byTrueWeight) and arbitrary extra attributes.
Cursor-based stock feed across stores (POST /b2b/v1/stocks/query). Returns {stocks: [{product_id, quantity, shelf_type, store_id}], cursor}; iterate until a page has fewer items than limit for a full snapshot. Known shelf_type values (open-ended): store, markdown, incoming, out, trash, lost, found, office, parcel, parcel_returned, collection, cargo, repacking, review, kitchen_on_demand, kitchen_components, kitchen_trash, kitchen_lost, kitchen_found. Sellable stock normally lives on shelf_type "store".
Escape hatch: direct call to any Yango Tech Retail B2B endpoint — for paths without a dedicated tool (orders/update, receipts/documents/upload, wms/picking/set-state, logistics/delivery/set-state, products-vat/*, pricelists/get|create, store-pricelist-links/*, 3pl/deliveries/*). Every endpoint of this API is a POST with a JSON body; pass a relative path like "b2b/v1/pricelists/get" and the body object. CAUTION: this tool can perform writes; 5xx/network errors are never retried for it.
Sets product prices in price lists (POST /b2b/v1/prices/set), at most 100 per request. Prices are decimal STRINGS (e.g. "150.00"); price_per_quantity (pack size the price applies to) defaults to 1 when omitted. The response body is not documented upstream (2xx = success) and is returned verbatim. There is no delete endpoint for prices.
Writes stock quantities for one store. mode=modify (default) POSTs /b2b/v1/stocks/update with update_mode "modify" (at most 1000 items per request); mode=initialize POSTs /b2b/v1/stocks/initialize for the first-time stock load of a store. The response body is not documented upstream (2xx = success) and is returned verbatim. Verify the result with query_stocks.
create_discounts lacks documentation on the exact key names inside discount_activity_period and discount_value maps. The description says 'Key names are undocumented upstream, passed through verbatim', which is an admission of incomplete API coverage. LLMs cannot guess the correct structure without examples or a schema.
Tool annotations (readOnlyHint, destructiveHint, idempotentHint) are listed in features but their actual presence in tool registration code is not verified. If present only in feature summary but not in explicit tool definitions, this is unverified.
Error recovery guidance is minimal. Most tools note '2xx = success' with response bodies 'returned verbatim', but do not explain what LLMs should do on a 4xx or 5xx failure. Guidance like 'retry with backoff' or 'check trace ID' is in INSTRUCTIONS but not per-tool.
Batch operation caps (100 products, prices, discounts; 1000 stocks) are documented in the tool descriptions but not as formal minItems/maxItems constraints in every array schema. Some are present (e.g., create_products has maxItems=100), but others (e.g., set_prices) do document the limit but the schema shows maxItems=100, which is correct. Consistency is good, but verify all batch operations have explicit min/max.