hepsiburada-mcp 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- hepsiburada_mcp-0.1.0/.github/workflows/publish.yml +20 -0
- hepsiburada_mcp-0.1.0/.github/workflows/registry.yml +61 -0
- hepsiburada_mcp-0.1.0/LICENSE +21 -0
- hepsiburada_mcp-0.1.0/PKG-INFO +113 -0
- hepsiburada_mcp-0.1.0/README-fa.md +83 -0
- hepsiburada_mcp-0.1.0/README-tr.md +83 -0
- hepsiburada_mcp-0.1.0/README.md +101 -0
- hepsiburada_mcp-0.1.0/pyproject.toml +22 -0
- hepsiburada_mcp-0.1.0/server.json +1 -0
- hepsiburada_mcp-0.1.0/src/hepsiburada_mcp/__init__.py +1 -0
- hepsiburada_mcp-0.1.0/src/hepsiburada_mcp/http.py +88 -0
- hepsiburada_mcp-0.1.0/src/hepsiburada_mcp/products.py +304 -0
- hepsiburada_mcp-0.1.0/src/hepsiburada_mcp/server.py +135 -0
- hepsiburada_mcp-0.1.0/tests/__init__.py +0 -0
- hepsiburada_mcp-0.1.0/tests/fixtures/home-categories.html +11 -0
- hepsiburada_mcp-0.1.0/tests/fixtures/product-iphone15.html +14 -0
- hepsiburada_mcp-0.1.0/tests/fixtures/search-iphone.html +5 -0
- hepsiburada_mcp-0.1.0/tests/test_live.py +104 -0
- hepsiburada_mcp-0.1.0/tests/test_products.py +181 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags: ["v*"]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
publish:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
permissions:
|
|
11
|
+
id-token: write # required for PyPI trusted publishing (OIDC)
|
|
12
|
+
contents: read
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
- uses: actions/setup-python@v5
|
|
16
|
+
with:
|
|
17
|
+
python-version: "3.12"
|
|
18
|
+
- run: pip install build
|
|
19
|
+
- run: python -m build
|
|
20
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
name: Publish to MCP Registry
|
|
2
|
+
|
|
3
|
+
# Official MCP Registry (registry.modelcontextprotocol.io) via GitHub OIDC.
|
|
4
|
+
# No secret, no interactive login: the runner's OIDC token proves ownership
|
|
5
|
+
# of the io.github.mohammad-abbasi-sh/* namespace.
|
|
6
|
+
# Refs: https://github.com/modelcontextprotocol/registry
|
|
7
|
+
|
|
8
|
+
on:
|
|
9
|
+
push:
|
|
10
|
+
tags: ["v*"]
|
|
11
|
+
workflow_dispatch:
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
publish:
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
permissions:
|
|
17
|
+
id-token: write # required for OIDC -> MCP Registry
|
|
18
|
+
contents: read
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@v4
|
|
21
|
+
|
|
22
|
+
- name: Sync server.json version to tag
|
|
23
|
+
# Only sync when running on a version tag (v*). On workflow_dispatch
|
|
24
|
+
# (ref = refs/heads/main) keep the version committed in server.json.
|
|
25
|
+
run: |
|
|
26
|
+
VER=""
|
|
27
|
+
if [[ "$GITHUB_REF" == refs/tags/* ]]; then
|
|
28
|
+
TAG="${GITHUB_REF#refs/tags/}"
|
|
29
|
+
VER="${TAG#v}"
|
|
30
|
+
fi
|
|
31
|
+
if [ -n "$VER" ]; then
|
|
32
|
+
python3 - "$VER" << 'EOF'
|
|
33
|
+
import json, sys
|
|
34
|
+
ver = sys.argv[1]
|
|
35
|
+
d = json.load(open('server.json'))
|
|
36
|
+
d['version'] = ver
|
|
37
|
+
for pkg in d.get('packages', []):
|
|
38
|
+
pkg['version'] = ver
|
|
39
|
+
json.dump(d, open('server.json', 'w'), indent=2, ensure_ascii=False)
|
|
40
|
+
print('server.json version ->', ver)
|
|
41
|
+
EOF
|
|
42
|
+
else
|
|
43
|
+
echo "No version tag ($GITHUB_REF); keeping server.json version as-is"
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
- name: Install mcp-publisher
|
|
47
|
+
run: |
|
|
48
|
+
curl -sL "https://github.com/modelcontextprotocol/registry/releases/download/v1.8.7/mcp-publisher_linux_amd64.tar.gz" -o /tmp/mcp-publisher.tar.gz
|
|
49
|
+
tar -xzf /tmp/mcp-publisher.tar.gz -C /tmp
|
|
50
|
+
sudo mv /tmp/mcp-publisher /usr/local/bin/mcp-publisher
|
|
51
|
+
mcp-publisher --version
|
|
52
|
+
|
|
53
|
+
- name: Validate server.json
|
|
54
|
+
run: mcp-publisher validate server.json
|
|
55
|
+
|
|
56
|
+
- name: Publish to MCP Registry (OIDC)
|
|
57
|
+
run: |
|
|
58
|
+
mcp-publisher login github-oidc
|
|
59
|
+
mcp-publisher publish server.json
|
|
60
|
+
# A registry outage must never break the release; re-run from Actions if needed.
|
|
61
|
+
continue-on-error: true
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Mohammad Abbasi
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: hepsiburada-mcp
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Unofficial read-only MCP server for hepsiburada.com shopping (search, product details, reviews, categories, price stats)
|
|
5
|
+
Author: Mohammad Abbasi
|
|
6
|
+
License: MIT
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Requires-Python: >=3.10
|
|
9
|
+
Requires-Dist: curl-cffi>=0.7
|
|
10
|
+
Requires-Dist: mcp<2
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
|
|
13
|
+
# hepsiburada-mcp 🇹🇷
|
|
14
|
+
|
|
15
|
+
mcp-name: io.github.mohammad-abbasi-sh/hepsiburada-mcp
|
|
16
|
+
|
|
17
|
+
Unofficial **read-only** MCP server for **hepsiburada.com**, Türkiye's leading e-commerce marketplace — search millions of products, read product details (price, stock, seller, GTIN, highlights), read customer reviews, browse the 9 top categories, and get price statistics (min / median / mean / max) for any query.
|
|
18
|
+
|
|
19
|
+
> Built by Mohammad Abbasi as part of the "Turkey MCP factory" (Sepehr-style pipeline). Not affiliated with hepsiburada.com.
|
|
20
|
+
|
|
21
|
+
## For AI agents
|
|
22
|
+
|
|
23
|
+
Add to your MCP client config (stdio):
|
|
24
|
+
|
|
25
|
+
```json
|
|
26
|
+
{
|
|
27
|
+
"mcpServers": {
|
|
28
|
+
"hepsiburada": {
|
|
29
|
+
"command": "uvx",
|
|
30
|
+
"args": ["hepsiburada-mcp"]
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Or run locally: `python -m hepsiburada_mcp.server` (needs `mcp<2`, `curl-cffi`).
|
|
37
|
+
|
|
38
|
+
## Tools
|
|
39
|
+
|
|
40
|
+
| Tool | Description |
|
|
41
|
+
|------|-------------|
|
|
42
|
+
| `hepsiburada_search` | Search products by keyword — `query` ("iphone", "kablosuz kulaklık"), `sort` ("relevance" / "price_asc" / "price_desc"), `limit` 1..24, `page` 1-based; returns title, price in TRY, rating, review count, URL, SKU, image, campaign |
|
|
43
|
+
| `hepsiburada_product_detail` | Detail of one product (`product` = full URL or path with "-p-HBCV…"): name, brand, price in TRY, stock status, rating, review count, seller (+ official-seller flag), category path, color, GTIN, images, highlights |
|
|
44
|
+
| `hepsiburada_list_categories` | The 9 top categories: Turkish name, URL, category id |
|
|
45
|
+
| `hepsiburada_price_stats` | Price statistics for a query: count, min / median / mean / max price in TRY across the first page |
|
|
46
|
+
| `hepsiburada_product_reviews` | Recent customer reviews of one product: author, star rating, review text, date |
|
|
47
|
+
|
|
48
|
+
Example output (`hepsiburada_search` / "iphone"):
|
|
49
|
+
|
|
50
|
+
```json
|
|
51
|
+
{"query": "iphone", "sort": "relevance", "page": 1, "count": 3, "products": [
|
|
52
|
+
{"title": "Apple iPhone 15 128 GB Mavi",
|
|
53
|
+
"url": "https://www.hepsiburada.com/apple-iphone-15-128-gb-mavi-p-HBCV00004X9ZCK",
|
|
54
|
+
"sku": "HBCV00004X9ZCK", "price_try": 56999.0, "rating": 4.8,
|
|
55
|
+
"review_count": 13102, "campaign": "30 günün en düşük fiyatı"}, …]}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Example output (`hepsiburada_product_detail` / iPhone 15):
|
|
59
|
+
|
|
60
|
+
```json
|
|
61
|
+
{"name": "Apple iPhone 15 128 GB", "sku": "HBCV00004X9ZCK", "brand": "Apple",
|
|
62
|
+
"category": "Telefon > Cep Telefonu > iPhone iOS Telefonlar", "color": "Mavi",
|
|
63
|
+
"gtin": "0195949036583", "price_try": 56999.0, "price_currency": "TRY",
|
|
64
|
+
"in_stock": true, "rating": 4.8, "review_count": 13102,
|
|
65
|
+
"seller": "Hepsiburada", "official_seller": true,
|
|
66
|
+
"highlights": ["Ekran : 6.1 inç Super Retina XDR OLED, …"], …}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Example output (`hepsiburada_price_stats` / "iphone"):
|
|
70
|
+
|
|
71
|
+
```json
|
|
72
|
+
{"query": "iphone", "sort": "relevance", "count": 3, "min_try": 56999.0,
|
|
73
|
+
"median_try": 102999.0, "mean_try": 91115.67, "max_try": 113349.0}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## How it works
|
|
77
|
+
|
|
78
|
+
hepsiburada.com returns HTTP 403 to plain HTTP clients, so the transport
|
|
79
|
+
uses Chrome TLS impersonation (`curl-cffi`, `chrome120`). There is no public
|
|
80
|
+
JSON API — data comes from the site's server-rendered HTML: search pages
|
|
81
|
+
carry product cards, product pages carry schema.org Product JSON-LD plus a
|
|
82
|
+
seller block and a "Ürün Özellikleri" highlights list, and the homepage
|
|
83
|
+
carries the top categories. Requests are spaced ~0.8s apart; everything is
|
|
84
|
+
read-only, no login, no API key.
|
|
85
|
+
|
|
86
|
+
## Install
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
uvx hepsiburada-mcp # run directly (needs uv)
|
|
90
|
+
# or
|
|
91
|
+
pip install hepsiburada-mcp
|
|
92
|
+
hepsiburada-mcp # starts the MCP server on stdio
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Tests
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
python -m venv .venv && .venv/bin/pip install -e .
|
|
99
|
+
.venv/bin/python -m unittest discover -s tests -v
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Offline tests run on recorded fixtures (real pages fetched 2026-11-06);
|
|
103
|
+
live tests hit hepsiburada.com.
|
|
104
|
+
|
|
105
|
+
## Roadmap
|
|
106
|
+
|
|
107
|
+
- Category-scoped search (search within one `-c-…` category)
|
|
108
|
+
- Seller store pages (other sellers of the same product)
|
|
109
|
+
- Price history (track a SKU over days)
|
|
110
|
+
|
|
111
|
+
## License
|
|
112
|
+
|
|
113
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# hepsiburada-mcp 🇹🇷
|
|
2
|
+
|
|
3
|
+
mcp-name: io.github.mohammad-abbasi-sh/hepsiburada-mcp
|
|
4
|
+
|
|
5
|
+
سرور MCP غیررسمی و **فقطخواندنی** برای **hepsiburada.com**، بزرگترین
|
|
6
|
+
فروشگاه اینترنتی ترکیه — جستوجو در میلیونها کالا، خواندن جزئیات کالا
|
|
7
|
+
(قیمت، موجودی، فروشنده، GTIN، ویژگیهای برجسته)، خواندن نظرهای مشتریان،
|
|
8
|
+
مرور ۹ دستهی اصلی، و گرفتن آمار قیمت (کمترین / میانه / میانگین /
|
|
9
|
+
بیشترین) برای هر جستوجو.
|
|
10
|
+
|
|
11
|
+
> ساختهی محمد عباسی در چارچوب «کارخانهی MCP ترکیه» (به سبک سپهر). هیچ
|
|
12
|
+
> وابستگیای به hepsiburada.com ندارد.
|
|
13
|
+
|
|
14
|
+
## برای ایجنتهای هوش مصنوعی
|
|
15
|
+
|
|
16
|
+
به پیکربندی MCP client خود اضافه کنید (stdio):
|
|
17
|
+
|
|
18
|
+
```json
|
|
19
|
+
{
|
|
20
|
+
"mcpServers": {
|
|
21
|
+
"hepsiburada": {
|
|
22
|
+
"command": "uvx",
|
|
23
|
+
"args": ["hepsiburada-mcp"]
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
یا بهصورت محلی اجرا کنید: `python -m hepsiburada_mcp.server`
|
|
30
|
+
(نیازمند `mcp<2` و `curl-cffi`).
|
|
31
|
+
|
|
32
|
+
## ابزارها
|
|
33
|
+
|
|
34
|
+
| ابزار | توضیح |
|
|
35
|
+
|------|-------|
|
|
36
|
+
| `hepsiburada_search` | جستوجوی کالا با کلیدواژه — `query` (مثل «iphone» یا «kablosuz kulaklık»)، `sort` («relevance» / «price_asc» / «price_desc»)، `limit` از ۱ تا ۲۴، `page` از ۱؛ برمیگرداند: عنوان، قیمت به لیر، امتیاز، تعداد نظر، آدرس، SKU، عکس، کمپین |
|
|
37
|
+
| `hepsiburada_product_detail` | جزئیات یک کالا (`product` = آدرس کامل یا مسیر حاوی «-p-HBCV…»): نام، برند، قیمت به لیر، وضعیت موجودی، امتیاز، تعداد نظر، فروشنده (+ فروشندهی رسمی)، مسیر دسته، رنگ، GTIN، عکسها، ویژگیهای برجسته |
|
|
38
|
+
| `hepsiburada_list_categories` | ۹ دستهی اصلی: نام ترکی، آدرس، شناسهی دسته |
|
|
39
|
+
| `hepsiburada_price_stats` | آمار قیمت برای یک جستوجو: تعداد، کمترین / میانه / میانگین / بیشترین قیمت (لیر) |
|
|
40
|
+
| `hepsiburada_product_reviews` | نظرهای اخیر مشتریان برای یک کالا: نویسنده، امتیاز ستارهای، متن نظر، تاریخ |
|
|
41
|
+
|
|
42
|
+
نمونهی خروجی (`hepsiburada_search` / «iphone»):
|
|
43
|
+
|
|
44
|
+
```json
|
|
45
|
+
{"query": "iphone", "count": 3, "products": [
|
|
46
|
+
{"title": "Apple iPhone 15 128 GB Mavi",
|
|
47
|
+
"url": "https://www.hepsiburada.com/apple-iphone-15-128-gb-mavi-p-HBCV00004X9ZCK",
|
|
48
|
+
"sku": "HBCV00004X9ZCK", "price_try": 56999.0, "rating": 4.8,
|
|
49
|
+
"review_count": 13102}, …]}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## چطور کار میکند؟
|
|
53
|
+
|
|
54
|
+
سایت hepsiburada.com به کلاینتهای HTTP ساده خطای 403 میدهد؛ به همین
|
|
55
|
+
دلیل لایهی انتقال از جعل TLS کروم (`curl-cffi`، `chrome120`) استفاده
|
|
56
|
+
میکند. API عمومی JSON ندارد — دادهها از HTML رندرشدهی سمت سرور
|
|
57
|
+
میآیند: صفحههای جستوجو کارتهای کالا دارند، صفحههای کالا JSON-LD از
|
|
58
|
+
نوع Product بههمراه بلوک فروشنده و فهرست «Ürün Özellikleri»، و صفحهی
|
|
59
|
+
اصلی دستههای اصلی را دارد. درخواستها با فاصلهی حدود ۰٫۸ ثانیه
|
|
60
|
+
فرستاده میشوند؛ همهچیز فقطخواندنی است، بدون لاگین و بدون کلید API.
|
|
61
|
+
|
|
62
|
+
## نصب
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
uvx hepsiburada-mcp # اجرای مستقیم (نیازمند uv)
|
|
66
|
+
# یا
|
|
67
|
+
pip install hepsiburada-mcp
|
|
68
|
+
hepsiburada-mcp # اجرای سرور MCP روی stdio
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## تستها
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
python -m venv .venv && .venv/bin/pip install -e .
|
|
75
|
+
.venv/bin/python -m unittest discover -s tests -v
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
تستهای آفلاین روی نمونههای ضبطشده از صفحههای واقعی اجرا میشوند
|
|
79
|
+
(دریافتشده در ۲۰۲۶-۱۱-۰۶)؛ تستهای زنده به hepsiburada.com وصل میشوند.
|
|
80
|
+
|
|
81
|
+
## لایسنس
|
|
82
|
+
|
|
83
|
+
MIT — ببینید [LICENSE](LICENSE).
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# hepsiburada-mcp 🇹🇷
|
|
2
|
+
|
|
3
|
+
mcp-name: io.github.mohammad-abbasi-sh/hepsiburada-mcp
|
|
4
|
+
|
|
5
|
+
Türkiye'nin önde gelen e-ticaret pazaryeri **hepsiburada.com** için resmi
|
|
6
|
+
olmayan, **salt okunur** MCP sunucusu — milyonlarca üründe arama yapın,
|
|
7
|
+
ürün detaylarını okuyun (fiyat, stok, satıcı, GTIN, öne çıkan özellikler),
|
|
8
|
+
müşteri yorumlarını okuyun, 9 ana kategoriye göz atın ve herhangi bir
|
|
9
|
+
sorgu için fiyat istatistikleri (min / medyan / ortalama / maks) alın.
|
|
10
|
+
|
|
11
|
+
> Mohammad Abbasi tarafından "Turkey MCP factory" (Sepehr tarzı süreç)
|
|
12
|
+
> kapsamında geliştirildi. hepsiburada.com ile bağlantısı yoktur.
|
|
13
|
+
|
|
14
|
+
## Yapay zekâ ajanları için
|
|
15
|
+
|
|
16
|
+
MCP istemci yapılandırmanıza ekleyin (stdio):
|
|
17
|
+
|
|
18
|
+
```json
|
|
19
|
+
{
|
|
20
|
+
"mcpServers": {
|
|
21
|
+
"hepsiburada": {
|
|
22
|
+
"command": "uvx",
|
|
23
|
+
"args": ["hepsiburada-mcp"]
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
veya yerel çalıştırın: `python -m hepsiburada_mcp.server`
|
|
30
|
+
(`mcp<2`, `curl-cffi` gerekir).
|
|
31
|
+
|
|
32
|
+
## Araçlar
|
|
33
|
+
|
|
34
|
+
| Araç | Açıklama |
|
|
35
|
+
|------|----------|
|
|
36
|
+
| `hepsiburada_search` | Anahtar kelimeyle ürün arama — `query` ("iphone", "kablosuz kulaklık"), `sort` ("relevance" / "price_asc" / "price_desc"), `limit` 1..24, `page` 1'den başlar; başlık, TL fiyat, puan, yorum sayısı, URL, SKU, görsel, kampanya döndürür |
|
|
37
|
+
| `hepsiburada_product_detail` | Bir ürünün detayı (`product` = "-p-HBCV…" içeren URL veya yol): ad, marka, TL fiyat, stok durumu, puan, yorum sayısı, satıcı (+ resmi satıcı işareti), kategori yolu, renk, GTIN, görseller, öne çıkanlar |
|
|
38
|
+
| `hepsiburada_list_categories` | 9 ana kategori: Türkçe ad, URL, kategori kimliği |
|
|
39
|
+
| `hepsiburada_price_stats` | Bir sorgunun fiyat istatistikleri: adet, min / medyan / ortalama / maks fiyat (TL) |
|
|
40
|
+
| `hepsiburada_product_reviews` | Bir ürünün son müşteri yorumları: yazar, yıldız puanı, yorum metni, tarih |
|
|
41
|
+
|
|
42
|
+
Örnek çıktı (`hepsiburada_search` / "iphone"):
|
|
43
|
+
|
|
44
|
+
```json
|
|
45
|
+
{"query": "iphone", "count": 3, "products": [
|
|
46
|
+
{"title": "Apple iPhone 15 128 GB Mavi",
|
|
47
|
+
"url": "https://www.hepsiburada.com/apple-iphone-15-128-gb-mavi-p-HBCV00004X9ZCK",
|
|
48
|
+
"sku": "HBCV00004X9ZCK", "price_try": 56999.0, "rating": 4.8,
|
|
49
|
+
"review_count": 13102}, …]}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Nasıl çalışır?
|
|
53
|
+
|
|
54
|
+
hepsiburada.com düz HTTP istemcilerine HTTP 403 döndürür; bu yüzden
|
|
55
|
+
aktarım Chrome TLS taklidi (`curl-cffi`, `chrome120`) kullanır. Herkese
|
|
56
|
+
açık bir JSON API yoktur — veriler sitenin sunucu taraflı işlenmiş
|
|
57
|
+
HTML sayfalarından gelir: arama sayfaları ürün kartları, ürün sayfaları
|
|
58
|
+
schema.org Product JSON-LD + satıcı bloğu + "Ürün Özellikleri" listesi,
|
|
59
|
+
ana sayfa ise ana kategorileri taşır. İstekler ~0.8 sn arayla yapılır;
|
|
60
|
+
her şey salt okunurdur, giriş gerekmez, API anahtarı gerekmez.
|
|
61
|
+
|
|
62
|
+
## Kurulum
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
uvx hepsiburada-mcp # doğrudan çalıştır (uv gerekir)
|
|
66
|
+
# veya
|
|
67
|
+
pip install hepsiburada-mcp
|
|
68
|
+
hepsiburada-mcp # MCP sunucusunu stdio üzerinde başlatır
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Testler
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
python -m venv .venv && .venv/bin/pip install -e .
|
|
75
|
+
.venv/bin/python -m unittest discover -s tests -v
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Çevrimdışı testler kayıtlı örnek sayfalarla çalışır (gerçek sayfalar,
|
|
79
|
+
2026-11-06); canlı testler hepsiburada.com'a bağlanır.
|
|
80
|
+
|
|
81
|
+
## Lisans
|
|
82
|
+
|
|
83
|
+
MIT — bkz. [LICENSE](LICENSE).
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# hepsiburada-mcp 🇹🇷
|
|
2
|
+
|
|
3
|
+
mcp-name: io.github.mohammad-abbasi-sh/hepsiburada-mcp
|
|
4
|
+
|
|
5
|
+
Unofficial **read-only** MCP server for **hepsiburada.com**, Türkiye's leading e-commerce marketplace — search millions of products, read product details (price, stock, seller, GTIN, highlights), read customer reviews, browse the 9 top categories, and get price statistics (min / median / mean / max) for any query.
|
|
6
|
+
|
|
7
|
+
> Built by Mohammad Abbasi as part of the "Turkey MCP factory" (Sepehr-style pipeline). Not affiliated with hepsiburada.com.
|
|
8
|
+
|
|
9
|
+
## For AI agents
|
|
10
|
+
|
|
11
|
+
Add to your MCP client config (stdio):
|
|
12
|
+
|
|
13
|
+
```json
|
|
14
|
+
{
|
|
15
|
+
"mcpServers": {
|
|
16
|
+
"hepsiburada": {
|
|
17
|
+
"command": "uvx",
|
|
18
|
+
"args": ["hepsiburada-mcp"]
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Or run locally: `python -m hepsiburada_mcp.server` (needs `mcp<2`, `curl-cffi`).
|
|
25
|
+
|
|
26
|
+
## Tools
|
|
27
|
+
|
|
28
|
+
| Tool | Description |
|
|
29
|
+
|------|-------------|
|
|
30
|
+
| `hepsiburada_search` | Search products by keyword — `query` ("iphone", "kablosuz kulaklık"), `sort` ("relevance" / "price_asc" / "price_desc"), `limit` 1..24, `page` 1-based; returns title, price in TRY, rating, review count, URL, SKU, image, campaign |
|
|
31
|
+
| `hepsiburada_product_detail` | Detail of one product (`product` = full URL or path with "-p-HBCV…"): name, brand, price in TRY, stock status, rating, review count, seller (+ official-seller flag), category path, color, GTIN, images, highlights |
|
|
32
|
+
| `hepsiburada_list_categories` | The 9 top categories: Turkish name, URL, category id |
|
|
33
|
+
| `hepsiburada_price_stats` | Price statistics for a query: count, min / median / mean / max price in TRY across the first page |
|
|
34
|
+
| `hepsiburada_product_reviews` | Recent customer reviews of one product: author, star rating, review text, date |
|
|
35
|
+
|
|
36
|
+
Example output (`hepsiburada_search` / "iphone"):
|
|
37
|
+
|
|
38
|
+
```json
|
|
39
|
+
{"query": "iphone", "sort": "relevance", "page": 1, "count": 3, "products": [
|
|
40
|
+
{"title": "Apple iPhone 15 128 GB Mavi",
|
|
41
|
+
"url": "https://www.hepsiburada.com/apple-iphone-15-128-gb-mavi-p-HBCV00004X9ZCK",
|
|
42
|
+
"sku": "HBCV00004X9ZCK", "price_try": 56999.0, "rating": 4.8,
|
|
43
|
+
"review_count": 13102, "campaign": "30 günün en düşük fiyatı"}, …]}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Example output (`hepsiburada_product_detail` / iPhone 15):
|
|
47
|
+
|
|
48
|
+
```json
|
|
49
|
+
{"name": "Apple iPhone 15 128 GB", "sku": "HBCV00004X9ZCK", "brand": "Apple",
|
|
50
|
+
"category": "Telefon > Cep Telefonu > iPhone iOS Telefonlar", "color": "Mavi",
|
|
51
|
+
"gtin": "0195949036583", "price_try": 56999.0, "price_currency": "TRY",
|
|
52
|
+
"in_stock": true, "rating": 4.8, "review_count": 13102,
|
|
53
|
+
"seller": "Hepsiburada", "official_seller": true,
|
|
54
|
+
"highlights": ["Ekran : 6.1 inç Super Retina XDR OLED, …"], …}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Example output (`hepsiburada_price_stats` / "iphone"):
|
|
58
|
+
|
|
59
|
+
```json
|
|
60
|
+
{"query": "iphone", "sort": "relevance", "count": 3, "min_try": 56999.0,
|
|
61
|
+
"median_try": 102999.0, "mean_try": 91115.67, "max_try": 113349.0}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## How it works
|
|
65
|
+
|
|
66
|
+
hepsiburada.com returns HTTP 403 to plain HTTP clients, so the transport
|
|
67
|
+
uses Chrome TLS impersonation (`curl-cffi`, `chrome120`). There is no public
|
|
68
|
+
JSON API — data comes from the site's server-rendered HTML: search pages
|
|
69
|
+
carry product cards, product pages carry schema.org Product JSON-LD plus a
|
|
70
|
+
seller block and a "Ürün Özellikleri" highlights list, and the homepage
|
|
71
|
+
carries the top categories. Requests are spaced ~0.8s apart; everything is
|
|
72
|
+
read-only, no login, no API key.
|
|
73
|
+
|
|
74
|
+
## Install
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
uvx hepsiburada-mcp # run directly (needs uv)
|
|
78
|
+
# or
|
|
79
|
+
pip install hepsiburada-mcp
|
|
80
|
+
hepsiburada-mcp # starts the MCP server on stdio
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Tests
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
python -m venv .venv && .venv/bin/pip install -e .
|
|
87
|
+
.venv/bin/python -m unittest discover -s tests -v
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Offline tests run on recorded fixtures (real pages fetched 2026-11-06);
|
|
91
|
+
live tests hit hepsiburada.com.
|
|
92
|
+
|
|
93
|
+
## Roadmap
|
|
94
|
+
|
|
95
|
+
- Category-scoped search (search within one `-c-…` category)
|
|
96
|
+
- Seller store pages (other sellers of the same product)
|
|
97
|
+
- Price history (track a SKU over days)
|
|
98
|
+
|
|
99
|
+
## License
|
|
100
|
+
|
|
101
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "hepsiburada-mcp"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Unofficial read-only MCP server for hepsiburada.com shopping (search, product details, reviews, categories, price stats)"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = { text = "MIT" }
|
|
11
|
+
requires-python = ">=3.10"
|
|
12
|
+
dependencies = [
|
|
13
|
+
"mcp<2",
|
|
14
|
+
"curl-cffi>=0.7",
|
|
15
|
+
]
|
|
16
|
+
authors = [{ name = "Mohammad Abbasi" }]
|
|
17
|
+
|
|
18
|
+
[project.scripts]
|
|
19
|
+
hepsiburada-mcp = "hepsiburada_mcp.server:main"
|
|
20
|
+
|
|
21
|
+
[tool.hatch.build.targets.wheel]
|
|
22
|
+
packages = ["src/hepsiburada_mcp"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"$schema":"https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json","description":"Unofficial read-only MCP server for hepsiburada.com shopping: search, details, reviews, prices.","name":"io.github.mohammad-abbasi-sh/hepsiburada-mcp","packages":[{"identifier":"hepsiburada-mcp","registryBaseUrl":"https://pypi.org","registryType":"pypi","transport":{"type":"stdio"},"version":"0.1.0"}],"repository":{"source":"github","url":"https://github.com/mohammad-abbasi-sh/hepsiburada-mcp"},"title":"hepsiburada.com Shopping","version":"0.1.0","websiteUrl":"https://github.com/mohammad-abbasi-sh/hepsiburada-mcp"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""hepsiburada_mcp — unofficial read-only MCP server for hepsiburada.com."""
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"""HTTP layer for hepsiburada_mcp — Chrome TLS impersonation required.
|
|
2
|
+
|
|
3
|
+
hepsiburada.com returns HTTP 403 to plain curl/httpx with a browser UA
|
|
4
|
+
(verified live 2026-11-06: 403 on homepage AND search with plain curl),
|
|
5
|
+
but answers HTTP 200 to curl-cffi chrome120 impersonation. There is no
|
|
6
|
+
public JSON API and no login involved — the site is server-rendered HTML,
|
|
7
|
+
so the transport must impersonate a real browser at the TLS level.
|
|
8
|
+
Requests are kept gentle (one at a time, ~0.8s apart) and read-only.
|
|
9
|
+
"""
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import time
|
|
13
|
+
from urllib.parse import quote_plus, urlparse
|
|
14
|
+
|
|
15
|
+
from curl_cffi import requests as _r
|
|
16
|
+
|
|
17
|
+
BASE = "https://www.hepsiburada.com"
|
|
18
|
+
TIMEOUT = 30.0
|
|
19
|
+
MIN_INTERVAL = 0.8 # seconds between requests — be polite
|
|
20
|
+
|
|
21
|
+
_HEADERS = {
|
|
22
|
+
"Accept-Language": "tr-TR,tr;q=0.9,en;q=0.8",
|
|
23
|
+
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
_last_fetch = 0.0
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class HepsiburadaError(RuntimeError):
|
|
30
|
+
pass
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _get(url: str) -> str:
|
|
34
|
+
global _last_fetch
|
|
35
|
+
wait = MIN_INTERVAL - (time.monotonic() - _last_fetch)
|
|
36
|
+
if wait > 0:
|
|
37
|
+
time.sleep(wait)
|
|
38
|
+
try:
|
|
39
|
+
resp = _r.get(url, impersonate="chrome120", headers=_HEADERS, timeout=TIMEOUT)
|
|
40
|
+
except Exception as e:
|
|
41
|
+
raise HepsiburadaError(f"network error fetching {url}: {e}") from e
|
|
42
|
+
finally:
|
|
43
|
+
_last_fetch = time.monotonic()
|
|
44
|
+
if resp.status_code == 403:
|
|
45
|
+
raise HepsiburadaError(
|
|
46
|
+
"hepsiburada.com refused the request (HTTP 403, bot wall) — try again later"
|
|
47
|
+
)
|
|
48
|
+
if resp.status_code == 429:
|
|
49
|
+
raise HepsiburadaError(
|
|
50
|
+
"hepsiburada.com rate-limited the request (HTTP 429) — try again later"
|
|
51
|
+
)
|
|
52
|
+
if resp.status_code == 404:
|
|
53
|
+
raise HepsiburadaError(f"page not found (HTTP 404): {url}")
|
|
54
|
+
if resp.status_code != 200:
|
|
55
|
+
raise HepsiburadaError(f"unexpected HTTP {resp.status_code} fetching {url}")
|
|
56
|
+
return resp.text
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def fetch_search_html(query: str, sort_param: str | None = None, page: int = 1) -> str:
|
|
60
|
+
"""Search page HTML. sort_param: 'artanfiyat' (price asc) or 'azalanfiyat' (price desc)."""
|
|
61
|
+
url = f"{BASE}/ara?q={quote_plus(query)}"
|
|
62
|
+
if sort_param:
|
|
63
|
+
url += f"&siralama={sort_param}"
|
|
64
|
+
if page > 1:
|
|
65
|
+
url += f"&sayfa={page}"
|
|
66
|
+
return _get(url)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def fetch_product_html(product: str) -> str:
|
|
70
|
+
"""Product page HTML. product: full URL, site path, or 'slug-p-HBCV…' path."""
|
|
71
|
+
path = product.strip()
|
|
72
|
+
if path.startswith("http"):
|
|
73
|
+
parsed = urlparse(path)
|
|
74
|
+
if "hepsiburada.com" not in parsed.netloc:
|
|
75
|
+
raise HepsiburadaError("product must be a hepsiburada.com URL or path")
|
|
76
|
+
path = parsed.path
|
|
77
|
+
if not path.startswith("/"):
|
|
78
|
+
path = "/" + path
|
|
79
|
+
if "-p-HBCV" not in path:
|
|
80
|
+
raise HepsiburadaError(
|
|
81
|
+
"product must be a product URL/path containing '-p-HBCV…' "
|
|
82
|
+
"(find one with hepsiburada_search first)"
|
|
83
|
+
)
|
|
84
|
+
return _get(f"{BASE}{path}")
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def fetch_home_html() -> str:
|
|
88
|
+
return _get(f"{BASE}/")
|