NoonMCP
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@NoonMCPfind the best discounted deals on headphones in the UAE"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
NoonMCP
An MCP server exposing noon.com's product catalog — search, browse, product detail, price comparison and discount scanning — to any MCP client (Claude Code, Claude Desktop, or your own agent).
Defaults to the UAE storefront (prices in AED); all seven GCC/MENA storefronts are supported.
Tools
Tool | What it does |
| Keyword search, with price / brand / deal-tag filters and sorting |
| List a category by its noon URL path |
| Scan categories and rank by discount, with quality gates |
| Full detail for one SKU: every seller's offer, specs, highlights |
| Several SKUs side by side, ranked by discount |
| Valid category slugs, deal-tag facets and sort fields |
| ChatGPT compatibility pair (see ChatGPT below) |
Every product result carries price (was), sale_price (current),
discount_percent, saving, rating, seller and a direct link.
Related MCP server: com.gladeapi/api
Transports
Command | Transport | For |
| stdio | Claude Desktop / Claude Code |
| Streamable HTTP on | ChatGPT connectors, remote clients |
| SSE on | Older remote MCP clients |
--host and --port override the bind address; NOON_TRANSPORT=http does the
same via environment.
Setup
pip install -r requirements.txt
python server.py # stdio
python server.py --http --port 8000ChatGPT
ChatGPT requires a remote server over HTTPS — it cannot reach localhost, so the server needs a tunnel or real hosting.
Its deep-research and company-knowledge paths also require two read-only tools
named exactly search and fetch, returning a fixed compatibility
schema (structuredContent plus the same JSON duplicated as text content).
Both are implemented and verified over the wire — search returns
{results: [{id, title, url}]} and fetch returns
{id, title, text, url, metadata}.
The id is the noon SKU, so ChatGPT can search then fetch a full product
record. The richer tools remain available to clients that allow arbitrary tools
(Claude, and ChatGPT developer mode).
Add it in ChatGPT under Settings → Connectors → Add custom connector, using
the /mcp URL.
Claude Code
claude mcp add noon -- python E:/Workspace/NoonMCP/server.pyClaude Desktop — claude_desktop_config.json
{
"mcpServers": {
"noon": {
"command": "python",
"args": ["E:/Workspace/NoonMCP/server.py"],
"env": { "NOON_LOCALE": "en-ae" }
}
}
}Environment (all transports)
Variable | Default | Notes |
|
|
|
|
| Hard cap on products per response |
|
| Bind address for HTTP transports |
|
| Port for HTTP transports |
|
|
|
|
| Logs go to stderr — stdout is the MCP transport |
All seven are verified against the live site.
x-mp-country must match the market. Hardcoding ae appears to work for
AE/OM/KW/BH/QA but makes SA and EG return zero hits with HTTP 200 — a silent
empty result rather than an error. The client derives it from the locale.
The Saudi storefront HTML returns 403 to this client, so the session cannot be warmed there; warmup falls back to another storefront, which seeds the same Akamai cookies.
How noon.com actually works
Reverse-engineered by instrumenting the live storefront in Chrome DevTools. These findings are what the implementation is built on.
Endpoints
GET /_vs/nc/mp-customer-catalog-api/api/v3/search?q=<query>
GET /_vs/nc/mp-customer-catalog-api/api/v3/u/<category-path>/
GET /_vs/nc/mp-customer-catalog-api/api/v3/product/<sku>
GET /_vs/nc/mp-customer-catalog-api/api/v3/u/desktop-navigation/<category-path> is exactly the path from the website URL, so
/uae-en/beauty/makeup-16142/ becomes .../api/v3/u/beauty/makeup-16142/.
Search and category listings share one schema: nbHits, nbPages, facets,
hits[].
Akamai Bot Manager — the load-bearing constraint
noon.com sits behind Akamai. On /_vs/ paths:
requests,httpx, Nodehttp2andcurlwithout nghttp2 all get their HTTP/2 stream reset withINTERNAL_ERROR— even carrying valid session cookies harvested from a real browser. The block keys on the TLS/HTTP2 fingerprint, not the session.Requests issued from Chrome DevTools via CDP are blocked too, while the page's own XHRs succeed — so in-browser scraping is not a way around it.
The fix is curl_cffi with Chrome
impersonation, reproducing Chrome's JA3/JA4 and HTTP/2 SETTINGS.
Swapping it for requests breaks the server.
Two further gotchas:
Warm up first. Fetch the storefront HTML once to seed the Akamai cookies (
AKA_A2,ak_bmsc,bm_s,bm_so). The first/_vs/call without this is reset.Send minimal headers. Only
accept,x-locale,x-mp-countryandreferer. Adding the frontend'sx-platform/x-content/x-cmsmakes search and listings reset — those belong only ondesktop-navigation. Replaying the browser's full header set also fails, because the frontend emitsx-ab-test:with an empty value and Envoy resets on it.
Pricing — easy to get backwards
{ "price": 56.92, // the WAS / reference price
"sale_price": 34.80 } // the CURRENT selling price; null when not discountedThere is no discount_percent field; it is computed here.
On product detail the shape differs: the name is product_title,
buying_options is empty, and pricing lives in variants[].offers[] —
one entry per seller, each with its own price, sale_price, stock and
store_name.
No discount sort
sort[by]=discount is silently ignored — the API falls back to popularity.
Supported sorts: popularity, price, best_rating, new_arrivals.
find_discounted_deals therefore pulls pages and ranks client-side, and the
client raises rather than pretending a discount sort worked.
Limits
limit caps at ~200 and nbPages at 50, so any single query reaches at most
~10,000 products.
Deal facets
Live counts observed on the Oman storefront (Electronics):
| Count |
| ~72,900 |
| ~97,800 |
| ~34,100 |
| ~245 |
Why find_discounted_deals is more than a threshold
Measured on live data, not assumed:
A bare "40% off" filter matched 54% of products carrying the
mega-dealtag, and the deepest "discounts" were filler — a 1.20 OMR pack of coat hangers marked down from 18.01. Hencemin_priceandmin_saving.noon lists every colourway as its own SKU, so one scan surfaced four Galaxy S25 Ultra colours and two identical roborock listings in a single top ten. Hence variant collapsing, which keeps the deepest discount per product.
A live 3-category scan: 600 products → 115 qualifying at ≥50% → 112 after collapsing, in 2.3s.
84.6% 6.42 (was 41.60) save 35.18 Man Eau de Toilette 100ml
78.5% 15.01 (was 69.72) save 54.71 Korean Brand Z8 Smart Watch
75.2% 19.52 (was 78.66) save 59.14 16 Inch Stand Fan, 60WScanning is the slow part — each category/tag/page is one request — so keep
pages_per_category small for interactive use.
Deploying as a remote server
Any Docker host works. Build and run:
docker build -t noon-mcp .
docker run -d --name noon-mcp --restart unless-stopped -p 8000:8000 -e NOON_LOCALE=en-ae noon-mcpOr with compose:
services:
noon-mcp:
build: .
restart: unless-stopped
ports: ["8000:8000"]
environment:
NOON_LOCALE: en-aeThe image defaults to NOON_TRANSPORT=http, so it serves Streamable HTTP on
:8000/mcp. Its healthcheck performs a real initialize round-trip rather than
a bare GET — a GET returns 406, because Streamable HTTP requires the client to
accept both application/json and text/event-stream, and it would pass even
if the MCP layer were broken.
ChatGPT needs HTTPS, so put it behind a reverse proxy or tunnel
(Caddy, Traefik, nginx, Cloudflare Tunnel, ngrok) and point the connector at
https://your-host/mcp.
The endpoint is unauthenticated. It is read-only against public noon data, but anyone with the URL can call it — add a proxy-level token or access policy if that matters to you.
Tests
python -m pytest tests/ -q # 17 tests, no network requiredSDK pin
requirements.txt pins mcp>=1.2,<2. The v2 SDK renamed FastMCP to
MCPServer and changed the tool and transport APIs; this server targets the v1
API it was built and tested against. Without the pin a fresh install picks up
2.x and the server fails to import.
Notes
This reads the same public JSON the website serves to any visitor. Requests are throttled (0.3s) and retried with backoff; keep concurrency modest.
It depends on an internal, undocumented API. noon can change field names, paths or bot rules without notice. If everything starts returning errors, check whether the header set or impersonation profile still passes.
This server cannot be deployed
Maintenance
Related MCP Connectors
Amazon product API & MCP server: search, prices, reviews, sellers, deals, and ASIN lookup by Canopy.
Google Shopping products, prices, sellers, and deals as structured data via a hosted MCP server.
Search multi-merchant supply, checkout, and track orders via MCP.
Product identity, pack sizes and feed/page checks. Free small trials; paid calls from $0.0003.
Related MCP Servers
- AlicenseAqualityCmaintenanceEnables querying and comparing prices, availability, ratings, reviews, and seller details from major Russian and Chinese marketplaces (Wildberries, Ozon, Yandex Market, and others) without requiring API keys, via a unified MCP interface.425MIT
- AlicenseNot gradedqualityCmaintenanceProvides read-only access to normalized Amazon marketplace data, including product details, search, offers, reviews, sellers, categories, deals, best sellers, identifiers, stock, and sales estimates across 13 marketplaces.MIT
- AlicenseAqualityBmaintenanceEnables Ozon marketplace customer-side operations including product search, detailed product cards, reviews, seller comparisons, and delivery city selection via MCP.419MIT
- AlicenseAqualityBmaintenanceEnables querying DNS Shop product data via MCP: search, product details, reviews, specifications, variants, categories, brand catalogs, availability by city, and store listings.1218MIT