donanimhaber-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.
@@ -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,98 @@
1
+ Metadata-Version: 2.5
2
+ Name: donanimhaber-mcp
3
+ Version: 0.1.0
4
+ Summary: Unofficial read-only MCP server for donanimhaber.com tech news and forum (latest, search, article, sections, hot topics)
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
+ # donanimhaber-mcp 🇹🇷
14
+
15
+ mcp-name: io.github.mohammad-abbasi-sh/donanimhaber-mcp
16
+
17
+ Unofficial **read-only** MCP server for donanimhaber.com, Türkiye's leading technology news site + forum — latest tech news, keyword search, full article text, section listings and the forum's hottest topics.
18
+
19
+ > Built by Mohammad Abbasi as part of the "Turkey MCP factory" (Sepehr-style pipeline). Not affiliated with donanimhaber.com.
20
+
21
+ ## For AI agents
22
+
23
+ Add to your MCP client config (stdio):
24
+
25
+ ```json
26
+ {
27
+ "mcpServers": {
28
+ "donanimhaber": {
29
+ "command": "uvx",
30
+ "args": ["donanimhaber-mcp"]
31
+ }
32
+ }
33
+ }
34
+ ```
35
+
36
+ Or run locally: `python -m donanimhaber_mcp.server` (needs `mcp<2`, `curl-cffi`).
37
+
38
+ ## Tools
39
+
40
+ | Tool | Description |
41
+ |------|-------------|
42
+ | `donanimhaber_latest` | Latest tech news (homepage) — `limit` 1..50; articles (id, title, summary, category, views, comments, URL) |
43
+ | `donanimhaber_search_news` | Keyword search over recent news (title, summary, category) — `keyword`, `limit` 1..50 |
44
+ | `donanimhaber_get_article` | Full text of one article — `article`: the article URL, the `/<slug>--<id>` path, or a bare numeric id (looked up in the latest listings); returns headline, author, dates, section, description, full body, comment count, word count |
45
+ | `donanimhaber_section` | Articles in one section/topic — `slug` from `donanimhaber_sections` (e.g. "teknoloji-haberleri", "yapay-zeka", "bitcoin", "gta-6"), `limit` 1..50 |
46
+ | `donanimhaber_sections` | All news sections/topics (name + slug + URL) from the homepage |
47
+ | `donanimhaber_forum_hot` | Hottest topics on the DonanımHaber forum right now — `limit` 1..50; topics (id, title, time ago, forum, online users, URL) |
48
+
49
+ Example output (`donanimhaber_latest` / 2026-11-07):
50
+
51
+ ```json
52
+ {"total": 39, "articles": [
53
+ {"article_id": 212608, "title": "Yenilenen Volkswagen Virtus'un ilk fotoğrafları yayınlandı",
54
+ "category": "Otomobil Teknolojileri",
55
+ "url": "https://www.donanimhaber.com/yenilenen-volkswagen-virtus-un-ilk-fotograflari-yayinlandi--212608"}, …]}
56
+ ```
57
+
58
+ Example output (`donanimhaber_get_article` / Aina AI Ring):
59
+
60
+ ```json
61
+ {"headline": "Ekranlı ve mikrofonlu akıllı yüzük: Aina AI Ring",
62
+ "author": "Erkan Calp", "date_published": "2026-11-06T20:44:00+03:00",
63
+ "section": "Giyilebilir Teknolojiler", "word_count": 223, …}
64
+ ```
65
+
66
+ ## How it works
67
+
68
+ donanimhaber.com serves its news pages fully server-rendered — no login, no API key, no session cookies. Listing pages carry `<article>` cards (title, summary, category, Turkish-formatted views like "40,3b" = 40,300, comments; section cards also carry the publish date). Article pages carry a schema.org NewsArticle JSON-LD block (headline, author, dates, section, full articleBody, comment count). Forum popular topics are server-rendered rows on forum.donanimhaber.com. Transport uses Chrome TLS impersonation (`curl-cffi`, `chrome120`); requests are spaced ~0.8s apart; everything is read-only.
69
+
70
+ Two honest limitations, verified live 2026-11-07: (1) the site's own `/ara?q=…` search ignores the query string — it returns the same 2 stale "ara" articles for every keyword — and the search box is a token-gated Yandex/Elastic widget, so `donanimhaber_search_news` filters the freshly fetched latest + technology listings client-side instead (Turkish-aware, folds zekâ → zeka); (2) the forum search is token-gated the same way, so there is no forum keyword search — `donanimhaber_forum_hot` lists the server-rendered popular topics.
71
+
72
+ ## Install
73
+
74
+ ```bash
75
+ uvx donanimhaber-mcp # run directly (needs uv)
76
+ # or
77
+ pip install donanimhaber-mcp
78
+ donanimhaber-mcp # starts the MCP server on stdio
79
+ ```
80
+
81
+ ## Tests
82
+
83
+ ```bash
84
+ python -m venv .venv && .venv/bin/pip install -e .
85
+ .venv/bin/python -m unittest discover -s tests -v
86
+ ```
87
+
88
+ Offline tests run on recorded fixtures (real pages fetched 2026-11-07); live tests hit donanimhaber.com. 32/32 green at build time (18 offline + 14 live) plus an MCP stdio smoke test (39 latest articles, 80 hot forum topics).
89
+
90
+ ## Roadmap
91
+
92
+ - Forum category listings (`/<forum>--f<id>` topic lists)
93
+ - Most-read / most-commented rankings (the homepage carries them)
94
+ - Article comments (the article page links them)
95
+
96
+ ## License
97
+
98
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,86 @@
1
+ # donanimhaber-mcp 🇹🇷
2
+
3
+ mcp-name: io.github.mohammad-abbasi-sh/donanimhaber-mcp
4
+
5
+ سرور MCP غیررسمی و **فقط-خواندنی** برای donanimhaber.com، سایت پیشروی اخبار فناوری ترکیه + انجمن آن — تازه‌ترین اخبار فناوری، جست‌وجوی کلیدواژه، متن کامل خبر، فهرست بخش‌ها و داغ‌ترین موضوع‌های انجمن.
6
+
7
+ > ساخته‌شده توسط محمد عباسی در چارچوب «کارخانهٔ MCP ترکیه» (خط تولید به سبک سپهر). وابسته به donanimhaber.com نیست.
8
+
9
+ ## برای ایجنت‌های هوش مصنوعی
10
+
11
+ به پیکربندی MCP client خود اضافه کنید (stdio):
12
+
13
+ ```json
14
+ {
15
+ "mcpServers": {
16
+ "donanimhaber": {
17
+ "command": "uvx",
18
+ "args": ["donanimhaber-mcp"]
19
+ }
20
+ }
21
+ }
22
+ ```
23
+
24
+ یا به‌صورت محلی اجرا کنید: `python -m donanimhaber_mcp.server` (نیازمند `mcp<2` و `curl-cffi`).
25
+
26
+ ## ابزارها
27
+
28
+ | ابزار | توضیح |
29
+ |------|-------|
30
+ | `donanimhaber_latest` | تازه‌ترین اخبار فناوری (صفحهٔ اصلی) — `limit` ۱ تا ۵۰؛ خبرها (شناسه، عنوان، خلاصه، دسته، بازدید، نظر، URL) |
31
+ | `donanimhaber_search_news` | جست‌وجوی کلیدواژه در اخبار اخیر (عنوان، خلاصه، دسته) — `keyword`، `limit` ۱ تا ۵۰ |
32
+ | `donanimhaber_get_article` | متن کامل یک خبر — `article`: نشانی خبر، مسیر `/<slug>--<id>`، یا شناسهٔ عددی تنها (در تازه‌ترین فهرست‌ها جست‌وجو می‌شود)؛ تیتر، نویسنده، تاریخ‌ها، بخش، توضیح، متن کامل، تعداد نظر، تعداد کلمه |
33
+ | `donanimhaber_section` | خبرهای یک بخش/موضوع — `slug` از خروجی `donanimhaber_sections` (مثلاً «teknoloji-haberleri»، «yapay-zeka»، «bitcoin»، «gta-6»)، `limit` ۱ تا ۵۰ |
34
+ | `donanimhaber_sections` | همهٔ بخش‌ها/موضوع‌های خبری (نام + slug + URL) از صفحهٔ اصلی |
35
+ | `donanimhaber_forum_hot` | داغ‌ترین موضوع‌های انجمن DonanımHaber در حال حاضر — `limit` ۱ تا ۵۰؛ موضوع‌ها (شناسه، عنوان، زمان، انجمن، کاربران آنلاین، URL) |
36
+
37
+ خروجی نمونه (`donanimhaber_latest` / ۲۰۲۶-۱۱-۰۷):
38
+
39
+ ```json
40
+ {"total": 39, "articles": [
41
+ {"article_id": 212608, "title": "Yenilenen Volkswagen Virtus'un ilk fotoğrafları yayınlandı",
42
+ "category": "Otomobil Teknolojileri",
43
+ "url": "https://www.donanimhaber.com/yenilenen-volkswagen-virtus-un-ilk-fotograflari-yayinlandi--212608"}, …]}
44
+ ```
45
+
46
+ خروجی نمونه (`donanimhaber_get_article` / Aina AI Ring):
47
+
48
+ ```json
49
+ {"headline": "Ekranlı ve mikrofonlu akıllı yüzük: Aina AI Ring",
50
+ "author": "Erkan Calp", "date_published": "2026-11-06T20:44:00+03:00",
51
+ "section": "Giyilebilir Teknolojiler", "word_count": 223, …}
52
+ ```
53
+
54
+ ## نحوهٔ کار
55
+
56
+ donanimhaber.com صفحه‌های خبری را کاملاً سمت سرور رندر می‌کند — بدون ورود، کلید API و کوکی نشست. صفحه‌های فهرست کارت‌های `<article>` دارند (عنوان، خلاصه، دسته، بازدید با قالب ترکی مثل «40,3b» = ۴۰٬۳۰۰، نظرها؛ کارت‌های بخش تاریخ انتشار را هم دارند). صفحه‌های خبر بلوک NewsArticle از نوع JSON-LD از schema.org دارند (تیتر، نویسنده، تاریخ‌ها، بخش، articleBody کامل، تعداد نظر). موضوع‌های محبوب انجمن به‌صورت ردیف‌های سمت سرور در forum.donanimhaber.com هستند. انتقال با جعل TLS کروم انجام می‌شود (`curl-cffi`، `chrome120`)؛ درخواست‌ها با فاصلهٔ ‎~۰٫۸ ثانیه فرستاده می‌شوند؛ همه‌چیز فقط-خواندنی است.
57
+
58
+ دو محدودیت صادقانه که در ۲۰۲۶-۱۱-۰۷ به‌صورت زنده تأیید شد: (۱) جست‌وجوی `/ara?q=…` خود سایت رشتهٔ جست‌وجو را نادیده می‌گیرد — برای هر کلیدواژه همان ۲ خبر قدیمی «ara» را برمی‌گرداند — و جعبهٔ جست‌وجو یک ویجت Yandex/Elastic نیازمند توکن است؛ پس `donanimhaber_search_news` در عوض تازه‌ترین فهرست‌های دریافت‌شده + فناوری را سمت کاربر فیلتر می‌کند (حساس به ترکی، با تبدیل zekâ به zeka)؛ (۲) جست‌وجوی انجمن هم به همان شکل نیازمند توکن است، پس جست‌وجوی کلیدواژه برای انجمن وجود ندارد — `donanimhaber_forum_hot` موضوع‌های محبوب رندرشدهٔ سمت سرور را فهرست می‌کند.
59
+
60
+ ## نصب
61
+
62
+ ```bash
63
+ uvx donanimhaber-mcp # اجرای مستقیم (نیازمند uv)
64
+ # یا
65
+ pip install donanimhaber-mcp
66
+ donanimhaber-mcp # سرور MCP را روی stdio راه می‌اندازد
67
+ ```
68
+
69
+ ## تست‌ها
70
+
71
+ ```bash
72
+ python -m venv .venv && .venv/bin/pip install -e .
73
+ .venv/bin/python -m unittest discover -s tests -v
74
+ ```
75
+
76
+ تست‌های آفلاین روی صفحات ضبط‌شده اجرا می‌شوند (صفحات واقعی دریافت‌شده در ۲۰۲۶-۱۱-۰۷)؛ تست‌های زنده به donanimhaber.com وصل می‌شوند. در زمان ساخت ۳۲ از ۳۲ سبز بود (۱۸ آفلاین + ۱۴ زنده) به‌همراه یک تست دود MCP روی stdio (۳۹ خبر تازه، ۸۰ موضوع داغ انجمن).
77
+
78
+ ## نقشهٔ راه
79
+
80
+ - فهرست دسته‌های انجمن (فهرست موضوع‌های `/<forum>--f<id>`)
81
+ - رتبه‌بندی پربازدیدترین / پرنظرترین (در صفحهٔ اصلی هستند)
82
+ - نظرهای خبر (صفحهٔ خبر به آن‌ها پیوند می‌دهد)
83
+
84
+ ## مجوز
85
+
86
+ MIT — ببینید [LICENSE](LICENSE).
@@ -0,0 +1,86 @@
1
+ # donanimhaber-mcp 🇹🇷
2
+
3
+ mcp-name: io.github.mohammad-abbasi-sh/donanimhaber-mcp
4
+
5
+ donanimhaber.com için resmi olmayan **salt okunur** MCP sunucusu — Türkiye'nin lider teknoloji haber sitesi + forumu: en son teknoloji haberleri, anahtar kelime araması, haberlerin tam metni, bölüm listeleri ve forumun en sıcak konuları.
6
+
7
+ > Mohammad Abbasi tarafından "Turkey MCP factory" (Sepehr tarzı hat) kapsamında geliştirildi. donanimhaber.com ile bağlantısı yoktur.
8
+
9
+ ## Yapay zekâ ajanları için
10
+
11
+ MCP istemci yapılandırmanıza ekleyin (stdio):
12
+
13
+ ```json
14
+ {
15
+ "mcpServers": {
16
+ "donanimhaber": {
17
+ "command": "uvx",
18
+ "args": ["donanimhaber-mcp"]
19
+ }
20
+ }
21
+ }
22
+ ```
23
+
24
+ Veya yerel çalıştırın: `python -m donanimhaber_mcp.server` (`mcp<2`, `curl-cffi` gerekir).
25
+
26
+ ## Araçlar
27
+
28
+ | Araç | Açıklama |
29
+ |------|----------|
30
+ | `donanimhaber_latest` | En son teknoloji haberleri (ana sayfa) — `limit` 1..50; haberler (id, başlık, özet, kategori, görüntülenme, yorum, URL) |
31
+ | `donanimhaber_search_news` | Son haberlerde anahtar kelime araması (başlık, özet, kategori) — `keyword`, `limit` 1..50 |
32
+ | `donanimhaber_get_article` | Bir haberin tam metni — `article`: haber URL'si, `/<slug>--<id>` yolu veya yalın sayısal id (en son listelerde aranır); başlık, yazar, tarihler, bölüm, açıklama, tam metin, yorum sayısı, kelime sayısı |
33
+ | `donanimhaber_section` | Bir bölüm/konudaki haberler — `slug` (`donanimhaber_sections` çıktısından; örn. "teknoloji-haberleri", "yapay-zeka", "bitcoin", "gta-6"), `limit` 1..50 |
34
+ | `donanimhaber_sections` | Tüm haber bölümleri/konuları (ad + slug + URL), ana sayfadan |
35
+ | `donanimhaber_forum_hot` | DonanımHaber forumunun şu anki en sıcak konuları — `limit` 1..50; konular (id, başlık, süre, forum, çevrimiçi kullanıcı, URL) |
36
+
37
+ Örnek çıktı (`donanimhaber_latest` / 2026-11-07):
38
+
39
+ ```json
40
+ {"total": 39, "articles": [
41
+ {"article_id": 212608, "title": "Yenilenen Volkswagen Virtus'un ilk fotoğrafları yayınlandı",
42
+ "category": "Otomobil Teknolojileri",
43
+ "url": "https://www.donanimhaber.com/yenilenen-volkswagen-virtus-un-ilk-fotograflari-yayinlandi--212608"}, …]}
44
+ ```
45
+
46
+ Örnek çıktı (`donanimhaber_get_article` / Aina AI Ring):
47
+
48
+ ```json
49
+ {"headline": "Ekranlı ve mikrofonlu akıllı yüzük: Aina AI Ring",
50
+ "author": "Erkan Calp", "date_published": "2026-11-06T20:44:00+03:00",
51
+ "section": "Giyilebilir Teknolojiler", "word_count": 223, …}
52
+ ```
53
+
54
+ ## Nasıl çalışıyor?
55
+
56
+ donanimhaber.com haber sayfalarını tamamen sunucu taraflı render ediyor — giriş, API anahtarı ve oturum çerezi gerekmiyor. Listeleme sayfalarında `<article>` kartları bulunur (başlık, özet, kategori, "40,3b" = 40.300 gibi Türkçe formatlı görüntülenme, yorumlar; bölüm kartlarında ayrıca yayın tarihi). Haber sayfalarında schema.org NewsArticle JSON-LD bloğu bulunur (başlık, yazar, tarihler, bölüm, tam articleBody, yorum sayısı). Forumun popüler konuları forum.donanimhaber.com'da sunucu taraflı satırlar olarak yer alır. Aktarım Chrome TLS kimliğine bürünme kullanır (`curl-cffi`, `chrome120`); istekler ~0,8 sn arayla yapılır; her şey salt okunurdur.
57
+
58
+ 2026-11-07'de canlı doğrulanan iki dürüst kısıtlama: (1) sitenin kendi `/ara?q=…` araması sorguyu yok sayıyor — her anahtar kelime için aynı 2 eski "ara" haberini döndürüyor — ve arama kutusu token gerektiren bir Yandex/Elastic widget'ı; bu nedenle `donanimhaber_search_news`, yeni çekilen en son + teknoloji listelerini istemci tarafında filtreler (Türkçe duyarlı, zekâ → zeka dönüşümü yapar); (2) forum araması da aynı şekilde token gerektirir, bu yüzden forumda anahtar kelime araması yoktur — `donanimhaber_forum_hot` sunucu taraflı popüler konuları listeler.
59
+
60
+ ## Kurulum
61
+
62
+ ```bash
63
+ uvx donanimhaber-mcp # doğrudan çalıştır (uv gerekir)
64
+ # veya
65
+ pip install donanimhaber-mcp
66
+ donanimhaber-mcp # MCP sunucusunu stdio üzerinde başlatır
67
+ ```
68
+
69
+ ## Testler
70
+
71
+ ```bash
72
+ python -m venv .venv && .venv/bin/pip install -e .
73
+ .venv/bin/python -m unittest discover -s tests -v
74
+ ```
75
+
76
+ Çevrimdışı testler kayıtlı örnek sayfalarla çalışır (2026-11-07'de çekilen gerçek sayfalar); canlı testler donanimhaber.com'a bağlanır. Derleme anında 32/32 yeşil (18 çevrimdışı + 14 canlı) ve bir MCP stdio duman testi (39 en son haber, 80 sıcak forum konusu).
77
+
78
+ ## Yol haritası
79
+
80
+ - Forum kategori listeleri (`/<forum>--f<id>` konu listeleri)
81
+ - En çok okunan / en çok yorumlanan sıralamaları (ana sayfada yer alırlar)
82
+ - Haber yorumları (haber sayfası onlara bağlanır)
83
+
84
+ ## Lisans
85
+
86
+ MIT — bkz. [LICENSE](LICENSE).
@@ -0,0 +1,86 @@
1
+ # donanimhaber-mcp 🇹🇷
2
+
3
+ mcp-name: io.github.mohammad-abbasi-sh/donanimhaber-mcp
4
+
5
+ Unofficial **read-only** MCP server for donanimhaber.com, Türkiye's leading technology news site + forum — latest tech news, keyword search, full article text, section listings and the forum's hottest topics.
6
+
7
+ > Built by Mohammad Abbasi as part of the "Turkey MCP factory" (Sepehr-style pipeline). Not affiliated with donanimhaber.com.
8
+
9
+ ## For AI agents
10
+
11
+ Add to your MCP client config (stdio):
12
+
13
+ ```json
14
+ {
15
+ "mcpServers": {
16
+ "donanimhaber": {
17
+ "command": "uvx",
18
+ "args": ["donanimhaber-mcp"]
19
+ }
20
+ }
21
+ }
22
+ ```
23
+
24
+ Or run locally: `python -m donanimhaber_mcp.server` (needs `mcp<2`, `curl-cffi`).
25
+
26
+ ## Tools
27
+
28
+ | Tool | Description |
29
+ |------|-------------|
30
+ | `donanimhaber_latest` | Latest tech news (homepage) — `limit` 1..50; articles (id, title, summary, category, views, comments, URL) |
31
+ | `donanimhaber_search_news` | Keyword search over recent news (title, summary, category) — `keyword`, `limit` 1..50 |
32
+ | `donanimhaber_get_article` | Full text of one article — `article`: the article URL, the `/<slug>--<id>` path, or a bare numeric id (looked up in the latest listings); returns headline, author, dates, section, description, full body, comment count, word count |
33
+ | `donanimhaber_section` | Articles in one section/topic — `slug` from `donanimhaber_sections` (e.g. "teknoloji-haberleri", "yapay-zeka", "bitcoin", "gta-6"), `limit` 1..50 |
34
+ | `donanimhaber_sections` | All news sections/topics (name + slug + URL) from the homepage |
35
+ | `donanimhaber_forum_hot` | Hottest topics on the DonanımHaber forum right now — `limit` 1..50; topics (id, title, time ago, forum, online users, URL) |
36
+
37
+ Example output (`donanimhaber_latest` / 2026-11-07):
38
+
39
+ ```json
40
+ {"total": 39, "articles": [
41
+ {"article_id": 212608, "title": "Yenilenen Volkswagen Virtus'un ilk fotoğrafları yayınlandı",
42
+ "category": "Otomobil Teknolojileri",
43
+ "url": "https://www.donanimhaber.com/yenilenen-volkswagen-virtus-un-ilk-fotograflari-yayinlandi--212608"}, …]}
44
+ ```
45
+
46
+ Example output (`donanimhaber_get_article` / Aina AI Ring):
47
+
48
+ ```json
49
+ {"headline": "Ekranlı ve mikrofonlu akıllı yüzük: Aina AI Ring",
50
+ "author": "Erkan Calp", "date_published": "2026-11-06T20:44:00+03:00",
51
+ "section": "Giyilebilir Teknolojiler", "word_count": 223, …}
52
+ ```
53
+
54
+ ## How it works
55
+
56
+ donanimhaber.com serves its news pages fully server-rendered — no login, no API key, no session cookies. Listing pages carry `<article>` cards (title, summary, category, Turkish-formatted views like "40,3b" = 40,300, comments; section cards also carry the publish date). Article pages carry a schema.org NewsArticle JSON-LD block (headline, author, dates, section, full articleBody, comment count). Forum popular topics are server-rendered rows on forum.donanimhaber.com. Transport uses Chrome TLS impersonation (`curl-cffi`, `chrome120`); requests are spaced ~0.8s apart; everything is read-only.
57
+
58
+ Two honest limitations, verified live 2026-11-07: (1) the site's own `/ara?q=…` search ignores the query string — it returns the same 2 stale "ara" articles for every keyword — and the search box is a token-gated Yandex/Elastic widget, so `donanimhaber_search_news` filters the freshly fetched latest + technology listings client-side instead (Turkish-aware, folds zekâ → zeka); (2) the forum search is token-gated the same way, so there is no forum keyword search — `donanimhaber_forum_hot` lists the server-rendered popular topics.
59
+
60
+ ## Install
61
+
62
+ ```bash
63
+ uvx donanimhaber-mcp # run directly (needs uv)
64
+ # or
65
+ pip install donanimhaber-mcp
66
+ donanimhaber-mcp # starts the MCP server on stdio
67
+ ```
68
+
69
+ ## Tests
70
+
71
+ ```bash
72
+ python -m venv .venv && .venv/bin/pip install -e .
73
+ .venv/bin/python -m unittest discover -s tests -v
74
+ ```
75
+
76
+ Offline tests run on recorded fixtures (real pages fetched 2026-11-07); live tests hit donanimhaber.com. 32/32 green at build time (18 offline + 14 live) plus an MCP stdio smoke test (39 latest articles, 80 hot forum topics).
77
+
78
+ ## Roadmap
79
+
80
+ - Forum category listings (`/<forum>--f<id>` topic lists)
81
+ - Most-read / most-commented rankings (the homepage carries them)
82
+ - Article comments (the article page links them)
83
+
84
+ ## License
85
+
86
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,22 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "donanimhaber-mcp"
7
+ version = "0.1.0"
8
+ description = "Unofficial read-only MCP server for donanimhaber.com tech news and forum (latest, search, article, sections, hot topics)"
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
+ donanimhaber-mcp = "donanimhaber_mcp.server:main"
20
+
21
+ [tool.hatch.build.targets.wheel]
22
+ packages = ["src/donanimhaber_mcp"]
@@ -0,0 +1 @@
1
+ {"$schema":"https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json","description":"Unofficial read-only MCP server for donanimhaber.com tech news and forum: latest, search, articles.","name":"io.github.mohammad-abbasi-sh/donanimhaber-mcp","packages":[{"identifier":"donanimhaber-mcp","registryBaseUrl":"https://pypi.org","registryType":"pypi","transport":{"type":"stdio"},"version":"0.1.0"}],"repository":{"source":"github","url":"https://github.com/mohammad-abbasi-sh/donanimhaber-mcp"},"title":"donanimhaber.com Tech News","version":"0.1.0","websiteUrl":"https://github.com/mohammad-abbasi-sh/donanimhaber-mcp"}
@@ -0,0 +1 @@
1
+ """donanimhaber_mcp — unofficial read-only MCP server for donanimhaber.com."""
@@ -0,0 +1,86 @@
1
+ """HTTP layer for donanimhaber_mcp.
2
+
3
+ donanimhaber.com serves its news pages fully server-rendered —
4
+ no login, no API key (verified live 2026-11-07: homepage 200,
5
+ /teknoloji-haberleri 200, article pages 200, forum home 200).
6
+ The transport uses curl-cffi chrome120 impersonation, the same
7
+ proven pattern as the other Turkey-factory servers. Requests are
8
+ kept gentle (one at a time, ~0.8s apart) and read-only.
9
+
10
+ Caveats found while probing (documented, not worked around):
11
+ - The site's own search (/ara?q=...) ignores the query and
12
+ returns the same 2 stale "ara" articles for every keyword; the
13
+ search box and the forum search are token-gated Yandex/Elastic
14
+ widgets. Keyword search in this server therefore filters the
15
+ freshly fetched latest + tech listings client-side.
16
+ - The forum search needs a token + security key, so there is no
17
+ forum keyword search — forum_hot lists the SSR popular topics
18
+ and forum_topics lists a forum category's topics.
19
+ """
20
+ from __future__ import annotations
21
+
22
+ import time
23
+ from urllib.parse import quote
24
+
25
+ from curl_cffi import requests as _r
26
+
27
+ BASE = "https://www.donanimhaber.com"
28
+ FORUM_BASE = "https://forum.donanimhaber.com"
29
+ TIMEOUT = 30.0
30
+ MIN_INTERVAL = 0.8 # seconds between requests — be polite
31
+
32
+ _HEADERS = {
33
+ "Accept-Language": "tr-TR,tr;q=0.9,en;q=0.8",
34
+ "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
35
+ }
36
+
37
+ _last_fetch = 0.0
38
+
39
+
40
+ class DonanimhaberError(RuntimeError):
41
+ pass
42
+
43
+
44
+ def _get(url: str) -> str:
45
+ global _last_fetch
46
+ wait = MIN_INTERVAL - (time.monotonic() - _last_fetch)
47
+ if wait > 0:
48
+ time.sleep(wait)
49
+ try:
50
+ resp = _r.get(url, impersonate="chrome120", headers=_HEADERS, timeout=TIMEOUT)
51
+ except Exception as e:
52
+ raise DonanimhaberError(f"network error fetching {url}: {e}") from e
53
+ finally:
54
+ _last_fetch = time.monotonic()
55
+ if resp.status_code == 403:
56
+ raise DonanimhaberError(
57
+ "donanimhaber.com refused the request (HTTP 403, bot wall) — try again later"
58
+ )
59
+ if resp.status_code == 429:
60
+ raise DonanimhaberError(
61
+ "donanimhaber.com rate-limited the request (HTTP 429) — try again later"
62
+ )
63
+ if resp.status_code == 404:
64
+ raise DonanimhaberError(f"page not found (HTTP 404): {url}")
65
+ if resp.status_code != 200:
66
+ raise DonanimhaberError(f"unexpected HTTP {resp.status_code} fetching {url}")
67
+ return resp.text
68
+
69
+
70
+ def fetch_home() -> str:
71
+ return _get(f"{BASE}/")
72
+
73
+
74
+ def fetch_section(slug: str) -> str:
75
+ """Section/topic listing: /teknoloji-haberleri, /yapay-zeka, /bitcoin ..."""
76
+ return _get(f"{BASE}/{quote(slug.strip('/'))}")
77
+
78
+
79
+ def fetch_article(path: str) -> str:
80
+ """Article page: full URL or /<slug>--<id> path."""
81
+ url = path if path.startswith("http") else f"{BASE}/{path.lstrip('/')}"
82
+ return _get(url)
83
+
84
+
85
+ def fetch_forum_home() -> str:
86
+ return _get(f"{FORUM_BASE}/")