Web sitelerinden veri toplamak için kendi MCP sunucunuzu nasıl yazarsınız: yeni başlayanlar için adım adım rehber
Makale içeriği
- Giriş: bu rehberin sonunda ne elde edeceksiniz
- Ön hazırlık: araçlar, erişimler ve sistem gereksinimleri
- Temel kavramlar: mcp sunucusu nasıl çalışır ve yapay zeka ajanına neden gerekir
- Adım 1: projeyi oluşturuyoruz ve bağımlılıkları kuruyoruz
- Adım 2: i̇lk araçla minimal mcp sunucusunu yazıyoruz
- Adım 3: mcp sunucusunu yapay zeka istemcisine bağlıyoruz
- Adım 4: veri çıkarma araçlarını ekliyoruz
- Adım 5: mobil proxy'leri ve ip rotasyonunu bağlıyoruz
- Adım 6: sunucuyu güvenilir hale getiriyoruz: yeniden denemeler, gecikmeler, önbellek ve limitler
- Sonucu kontrol etme: hazır mcp sunucusu için kontrol listesi
- Mcp sunucusu oluştururken sık yapılan hatalar ve çözümleri
- Ek olanaklar: ileri düzeyler için bölüm
- Sss: mcp sunucusu oluşturma hakkında sık sorulan sorular
- Sonuç: ne yaptınız ve bundan sonra nereye
Giriş: Bu rehberin sonunda ne elde edeceksiniz
Yapay zeka asistanıyla bir sohbet açtığınızı ve şöyle yazdığınızı hayal edin: "Rakibin sayfasına git, kataloğdaki tüm ürünlerin adlarını ve fiyatlarını topla ve bir tabloya dök." Asistan "internete erişimim yok" demek yerine gerçekten sayfayı indirir, verileri çeker ve size hazır sonucu verir. Rehberi sonuna kadar takip ederek tam olarak bunu inşa edeceksiniz. Dil modeli ile web arasındaki bağlantı halkası, Python'da yazdığınız kendi MCP sunucunuz olacak.
Önemli bir uyarı: hazır Playwright MCP ve diğer kutu çözümlerini ele almayacağız. Blogda onlar hakkında ayrı içerikler var. Buradaki görev farklı: sunucuyu sıfırdan yazmak, böylece her satırı anlayacak, kendi araçlarınızı ekleyebilecek, mobil proxy'leri bağlayabilecek ve mantığı belirli görevlere uyarlayabileceksiniz. Kendi çözümünüz her zaman başkasınınkinden daha esnektir.
Bu rehber kimler için
- Bir geliştiriciye kazıma programı sipariş etmeden fiyatları, yorumları, ürün açıklamalarını ve rakip içeriğini hızlıca toplaması gereken pazarlamacılar ve işletme sahipleri.
- Teklifleri, açılış sayfalarını ve kreatifleri izleyen ve rutin işleri bir yapay zeka ajanına devretmek isteyen arbitrajcılar.
- MCP protokolünü duymuş ama henüz kendi sunucusunu kurmamış ve çalışan bir şablon isteyen geliştiriciler.
- Ajanın isteklerinin ev interneti yerine kendi proxy'lerinden geçmesini önemseyen mobil proxy kullanıcıları.
Önceden bilmeniz gerekenler
Rehber yeni başlayanlar için tasarlandı. Programlama deneyimi şart değil, ancak komut satırının ne olduğunu ve bir dosyanın metin düzenleyicide nasıl açıldığını bilmek işinize yarar. Tüm kodu olduğu gibi kopyalayabilirsiniz ve her parçası basit bir dille açıklanmıştır. Zaten Python yazıyorsanız, makalenin sonuna doğru sizin için ileri düzey bir bölüm var.
Ne kadar zaman gerekir
İlk geçiş için 2-3 saat planlayın. Araçların kurulumu yaklaşık 30 dakika sürer, çalışan minimal MCP sunucusu bir saat içinde ortaya çıkar ve kalan zaman veri çıkarma araçlarını eklemeye, proxy'yi bağlamaya ve test etmeye gider. Aynı şeyi başka bir bilgisayarda sıfırdan 20-30 dakikada tekrarlayabileceksiniz.
Ön hazırlık: Araçlar, erişimler ve sistem gereksinimleri
Kodu yazmadan önce ihtiyacınız olan her şeye sahip olduğunuzdan emin olun. Bu bölüm yarım saatte tamamlanabilir ve sonraki aşamalarda karşılaşılan tipik sorunların yarısını ortadan kaldırır.
Sistem gereksinimleri
- Windows 10/11, macOS 12 ve üzeri ya da Linux (Ubuntu 22.04 ve üzeri) yüklü bir bilgisayar. Anlatılan her şey bu sistemlerin tümünde çalışır, tek fark dosya yollarıdır.
- En az 4 GB RAM ve 1 GB boş disk alanı.
- Kararlı internet erişimi.
Kurulacaklar
- Python 3.11 veya üzeri. 2026 itibarıyla güncel sürümler 3.12 ve 3.13'tür. Python projesinin resmi sitesinden kurulum dosyasını indirin. Windows'ta kurulumun ilk ekranında mutlaka Add python.exe to PATH kutusunu işaretleyin, aksi halde python komutu terminalde bulunamaz. macOS'ta Python'u Homebrew ile brew install python komutuyla kurmak daha kolaydır. Ubuntu'da sudo apt install python3 python3-venv python3-pip komutunu çalıştırın.
- Kod için metin düzenleyici. Visual Studio Code'u öneriyoruz. Ücretsizdir, sözdizimini renklendirir ve hataları gösterir. Başka bir düzenleyici de olur, hatta Not Defteri bile, ama VS Code ile daha rahat edersiniz.
- MCP istemcisi, yani sunucuyu bağlayacağınız yapay zeka ajanı bulunan uygulama. Yeni başlayanlar için en basit seçenek: Claude Desktop. Ayrıca Cursor editörü, GitHub Copilot uzantılı VS Code ve başka araçlar da MCP'yi destekler. Çalışmaya başlamadan önce en az birini kurun.
- Node.js 20 veya üzeri. Sunucunun kendisi için değil, araçları hata ayıklamak için kullanacağımız MCP Inspector yardımcı programı için gerekli. Node.js'in resmi sitesinden LTS sürümünün kurulum dosyasını indirin ve varsayılan ayarlarla kurun.
Erişimler
Proxy bölümü için mobil proxy verileriniz gerekecek: host, port, kullanıcı adı ve şifre, ayrıca tarifeniz destekliyorsa IP değiştirme bağlantısı. Bunların hepsi sağlayıcının müşteri panelinde bulunur. Henüz proxy'niz yoksa rehberi onsuz da tamamlayabilirsiniz: sunucu doğrudan çalışır, proxy'yi sonradan tek satırla eklersiniz.
Yedekler
MCP istemcisinin yapılandırma dosyasını düzenleyeceğiz. Bundan önce dosyayı güvenli bir yere, örneğin masaüstüne "yedek" notuyla kopyalayın. Bir şey ters giderse kopyayı yerine koymanız yeterli. Sunucu kodunu ayrı bir klasörde tutun ve her çalışma adımından sonra dosyanın bir kopyasını kaydedin ya da Git kullanmayı biliyorsanız commit yapın.
İpucu: Diskte boşluksuz ve Kiril harfsiz kısa bir yol içeren ayrı bir klasör oluşturun, örneğin Windows'ta C:/mcp-collector ya da macOS ve Linux'ta ~/mcp-collector. Yollardaki boşluklar ve Rusça harfler yapılandırma dosyalarından sunucu başlatmayı düzenli olarak bozar ve nedeni bulmak için bir saat harcarsınız.
Temel kavramlar: MCP sunucusu nasıl çalışır ve yapay zeka ajanına neden gerekir
İlk kod satırını yazmadan önce terimleri netleştirelim. Bunu yapmadan talimatlar bir dizi sihirli söz gibi görünür, bunu yapınca her eylem mantıklı hale gelir.
MCP nedir
MCP (Model Context Protocol), dil modelinin dış araçlarla nasıl iletişim kurduğunu tanımlayan açık bir protokoldür. Ortaya çıkmasından önce her servis yapay zekaya "el vermenin" kendi yolunu icat ediyordu. MCP bunu standartlaştırdı: protokole uygun bir sunucu yazdıysanız, ister Claude Desktop, ister Cursor, ister kendi ajanınız olsun her uyumlu istemci onu anlar. MCP'yi bir USB girişine benzetebilirsiniz: ne bağladığınız önemli değil, flash bellek mi fare mi, giriş aynıdır.
İstemci ve sunucu
MCP mimarisinde iki taraf vardır. İstemci, sorular soran ve araçları çağıran yapay zeka uygulamasıdır. MCP sunucusu ise bu araçları sağlayan programdır. Bizim durumumuzda sunucu "internete gidip veri getirme" yeteneği olacak, istemci ise yapay zeka asistanınız olacak. Sunucu bilgisayarınızda yerel olarak çalışır ve istemci onunla doğrudan iletişim kurar.
Araçlar, kaynaklar ve istemler
MCP sunucusu istemciye üç tür varlık sunabilir:
- Araçlar (tools) — modelin çağırabileceği fonksiyonlar: "sayfayı indir", "tüm bağlantıları çıkar", "proxy IP'sini değiştir". Rehberimizin temeli budur.
- Kaynaklar (resources) — sunucunun okuma için sunduğu veriler, örneğin ayar dosyasının içeriği ya da son toplamanın sonucu.
- İstemler (prompts) — kullanıcının tek komutla çağırabileceği hazır istek şablonları.
Veri toplamak için araçlar yeterlidir. Kaynaklara ve istemlere ileri düzey bölümde değineceğiz.
Model neyi çağıracağını nasıl anlar
Burada önemli bir nüans var. İstemci sunucuya bağlandığında, araçların listesini adları, açıklamaları ve parametreleriyle birlikte ister. Bu açıklamalar modelin bağlamına girer. Sonra model, tam olarak açıklama metnine dayanarak hangi aracı hangi argümanlarla çağıracağına kendi karar verir. Bu nedenle kodumuzdaki fonksiyon açıklamaları formalite değil, yapay zeka için bir talimattır. Aracın ne yaptığını ve ne zaman kullanılacağını ne kadar net yazarsanız, ajan o kadar isabetli çalışır.
Taşıma katmanı: stdio ve HTTP
Sunucu ve istemcinin bir şekilde mesaj alışverişi yapması gerekir. Protokol iki temel yöntem öngörür. stdio — istemci betiğinizi alt süreç olarak kendisi başlatır ve standart giriş/çıkış üzerinden onunla konuşur. Yerel çalışma için en basit seçenektir ve bununla başlayacağız. Streamable HTTP — sunucu, istemcinin bir adres üzerinden bağlandığı bir web servisi olarak çalışır. Bu seçenek, sunucu uzak bir makinede yaşıyorsa veya birden fazla istemci ona bağlanıyorsa gereklidir. Bunu ileri düzey bölümde ele alacağız.
⚠️ Dikkat: stdio taşımasında sürecin tüm standart çıktısı protokolün servis mesajlarıyla doludur. Kodda hata ayıklama için normal bir print yazarsanız, istemci doğru yanıt yerine çöp alır ve bağlantıyı keser. Hata ayıklama mesajlarını yalnızca stderr hata akışına yazabilirsiniz. Bu kuralı unutmayın, size çok zaman kazandıracaktır.
MCP üzerinden veri toplamak neden kullanışlıdır
Klasik bir kazıyıcı sabit kodlanmıştır: belirli bir siteden belirli alanları toplar. Şablon değiştiği anda kazıyıcı bozulur. "Yapay zeka ajanı artı MCP sunucusu" ikilisi farklı çalışır: sunucu evrensel araçlar verir (indir, metni çıkar, seçiciye göre öğe bul), model ise sayfanın yapısını kendi çözer ve sonucu formüle eder. Her yeni kaynak için kod yazmadan esneklik elde edersiniz.
Adım 1: Projeyi oluşturuyoruz ve bağımlılıkları kuruyoruz
Bu aşamanın amacı: izole bir Python ortamı hazırlamak ve MCP sunucusu için gereken kütüphaneleri kurmak. Adımın sonunda çalışan bir sanal ortama sahip bir proje klasörünüz olacak.
Sanal ortam neden gerekir
Sanal ortam, proje klasörü içinde kendi kütüphaneleriyle birlikte ayrı bir Python kopyasıdır. Sunucumuzun bilgisayardaki diğer Python programlarıyla çakışmaması ve MCP istemcisinin hangi yorumlayıcıyı başlatacağını tam olarak bilmesi için gereklidir. Onsuz "terminalde çalışıyor ama istemcide çalışmıyor" sorunlarının yarısı garanti.
Adım adım talimat
- Terminali açın. Windows'ta Win+R tuşlarına basın, powershell yazın ve Enter'a basın. macOS'ta Spotlight ile Terminal uygulamasını açın (Cmd+Boşluk, ardından Terminal yazın). Linux'ta Ctrl+Alt+T tuşlarına basın.
- Proje klasörünü oluşturun ve içine girin. Windows'ta iki komut çalıştırın: mkdir C:/mcp-collector, ardından cd C:/mcp-collector. macOS ve Linux'ta: mkdir ~/mcp-collector, ardından cd ~/mcp-collector.
- Python sürümünü python --version komutuyla kontrol edin (macOS ve Linux'ta python3 --version gerekebilir). Python 3.12.x gibi bir satır görmelisiniz. Sürüm 3.11'den düşükse ya da komut bulunamazsa hazırlık bölümüne dönün ve Python'u yeniden kurun.
- python -m venv .venv komutuyla sanal ortamı oluşturun. Proje klasöründe gizli bir .venv klasörü belirecek. Bu 10-20 saniye sürer.
- Ortamı etkinleştirin. Windows'ta PowerShell'de: .venv/Scripts/Activate.ps1. PowerShell betik çalıştırmanın yasak olduğunu söylerse Set-ExecutionPolicy -Scope CurrentUser RemoteSigned komutunu çalıştırın, Y harfiyle onaylayın ve etkinleştirmeyi tekrarlayın. macOS ve Linux'ta: source .venv/bin/activate. Etkinleştirmeden sonra terminal satırının başında (.venv) işareti görünecek.
- Paket yöneticisini güncelleyin: python -m pip install --upgrade pip.
- Kütüphaneleri tek komutla kurun: pip install "mcp[cli]" httpx beautifulsoup4. Burada mcp protokolün resmi Python SDK'sıdır (2026 itibarıyla güncel dal 1.x), httpx proxy destekli modern HTTP istek kütüphanesidir, beautifulsoup4 ise HTML ayrıştırma aracıdır. Kurulum 1-2 dakika sürer.
- Proje klasöründe boş bir server.py dosyası oluşturun. VS Code'da: File, Open Folder ile klasörü açın, ardından sol paneldeki yeni dosya simgesine tıklayıp adı yazın.
Kütüphaneler ne anlama gelir
- mcp tüm protokolü üstlenir: araç kaydı, mesaj alışverişi, parametre açıklaması. İçindeki FastMCP modülü bir aracı dekoratörlü normal bir fonksiyon olarak tanımlamanıza olanak tanır.
- httpx sayfaları indirir. Eski requests'in aksine HTTP/2, asenkron çalışma ve kolay proxy yapılandırması destekler.
- beautifulsoup4 HTML'i etiketlere ve CSS seçicilerine göre öğe aramanın kolay olduğu bir ağaca dönüştürür.
İpucu: Sanal ortam içindeki yorumlayıcının tam yolunu hemen not edin. Windows'ta bu C:/mcp-collector/.venv/Scripts/python.exe, macOS ve Linux'ta /Users/isim/mcp-collector/.venv/bin/python (Linux'ta /home/isim/...). İstemciye bağlanırken buna ihtiyacınız olacak. Tam yolu Windows'ta where python, macOS ve Linux'ta which python komutuyla ortam etkinken öğrenebilirsiniz.
✅ Kontrol: pip list komutunu çalıştırın. Listede mcp, httpx ve beautifulsoup4 paketleri bulunmalı. Ayrıca python -c "import mcp, httpx, bs4; print('ok')" komutunu çalıştırın — yanıt olarak hatasız ok kelimesi çıkmalı.
Olası sorunlar
- python komutu bulunamadı. Windows'ta Python'u Add to PATH kutusu işaretli olarak yeniden kurun. macOS'ta python yerine python3 kullanın.
- pip izin hatası veriyor. Muhtemelen ortam etkin değil ve paketleri sistem Python'una kuruyorsunuz. Satır başındaki (.venv) işaretini kontrol edin.
- Kurulumda derleme hatası. pip'i güncelleyip tekrar deneyin. İşe yaramazsa Python sürümünün 3.11'den düşük olmadığından emin olun.
Adım 2: İlk araçla minimal MCP sunucusunu yazıyoruz
Bu aşamanın amacı: bir adresteki sayfayı indirip HTML'ini döndüren tek araçlı çalışan bir MCP sunucusu yazmak. Bu, üzerine fonksiyon ekleyeceğimiz temeldir.
Sunucu kodu
server.py dosyasını açın ve aşağıdaki kodu tamamen yapıştırın:
import sys
import httpx
from mcp.server.fastmcp import FastMCP
mcp = FastMCP('web-collector')
HEADERS = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0 Safari/537.36',
'Accept-Language': 'ru-RU,ru;q=0.9,en;q=0.8',
}
def log(message: str) -> None:
print(message, file=sys.stderr)
@mcp.tool()
def fetch_page(url: str, max_chars: int = 20000) -> str:
'''Скачивает страницу по указанному URL и возвращает её HTML-код.
Используй, когда нужно посмотреть исходную разметку страницы.
Параметр max_chars ограничивает длину ответа, чтобы не переполнять контекст.'''
log(f'fetch_page: {url}')
with httpx.Client(headers=HEADERS, timeout=20.0, follow_redirects=True) as client:
response = client.get(url)
response.raise_for_status()
return response.text[:max_chars]
if __name__ == '__main__':
mcp.run()Kodu satır satır inceleyelim
- FastMCP('web-collector') web-collector adıyla sunucu nesnesi oluşturur. İstemci bu adı bağlı sunucular listesinde gösterir.
- HEADERS — sitelere gönderdiğimiz başlıklar. Birçok site, istek her zamanki tarayıcı User-Agent'ı olmadan geldiğinde eksik içerik veya hata döndürür. Accept-Language başlığı Rusça sayfa sürümünü istediğimizi belirtir.
- log fonksiyonu mesajları stderr'e yazar. Normal print yerine tam olarak böyle, çünkü stdout protokol tarafından kullanılıyor. Bu mesajları istemci günlüklerinde ve MCP Inspector'da göreceksiniz.
- @mcp.tool() — normal bir fonksiyonu MCP aracına dönüştüren dekoratör. SDK fonksiyon adını, parametre tiplerini ve docstring'i otomatik okur ve model için açıklama oluşturur. max_chars = 20000 varsayılan değeri parametrenin isteğe bağlı olduğu anlamına gelir.
- Üçlü tırnak içindeki docstring — yapay zekanın okuyacağı şey budur. Burada aracın ne yaptığını ve ne zaman kullanılacağını açıklıyoruz. Bu tür açıklamaları, ajanla konuştuğunuz dilde ayrıntılı yazın.
- follow_redirects=True parametreli httpx.Client yönlendirmeleri otomatik izler, timeout=20.0 ise isteğin sonsuza kadar asılı kalmasını engeller.
- raise_for_status() site 4xx veya 5xx kodu döndürdüyse hata fırlatır. SDK bunu yakalar ve istemciye sessizlik yerine anlaşılır bir hata mesajı döndürür.
- mcp.run() sunucuyu varsayılan olarak stdio taşımasıyla başlatır. İstemciden komut bekleyecektir.
MCP Inspector ile ilk kontrol
server.py'yi doğrudan çalıştırmak işe yaramaz: istemciden mesaj bekleyecek ve hiçbir şey göstermeyecektir. Kontrol için, istemciyi taklit eden ve araçları elle çağırmanıza olanak tanıyan bir web arayüzü olan MCP Inspector'ı kullanacağız.
- Sanal ortamın etkin ve proje klasöründe olduğunuzdan emin olun.
- mcp dev server.py komutunu çalıştırın. Bu komut, cli uzantılı kurulu mcp paketinin bir parçasıdır. İlk çalıştırmada Inspector'ı npx üzerinden indirir, bu yaklaşık bir dakika sürer.
- Terminalde http://localhost:6274 biçiminde bir adres ve yeni sürümlerde bir erişim tokenı belirir. Adresi tarayıcıda açın (genellikle kendiliğinden açılır).
- Inspector'ın sol panelinde STDIO taşımasının seçili olduğunu, komutun python, argümanların server.py olduğunu kontrol edin. Connect düğmesine basın.
- Durum göstergesi Connected yazısıyla yeşile döner. Üst menüden Tools sekmesine geçin ve List Tools'a basın.
- Listede docstring'den açıklaması ve iki parametresiyle fetch_page aracı görünecek. Üzerine tıklayın.
- url alanına https://example.com yazın, max_chars alanını boş bırakın veya 5000 yazın. Run Tool'a basın.
- Sağda sonuç görünecek: doctype etiketiyle başlayan sayfa HTML kodu. Altta, sunucu günlükleri sekmesinde fetch_page: https://example.com satırını göreceksiniz.
✅ Kontrol: Inspector Connected durumunu gösteriyor, Tools listesinde fetch_page var, example.com adresiyle çağrı hatasız HTML döndürüyor. Böyleyse ilk MCP sunucunuz çalışıyor.
Olası sorunlar
- mcp dev, npx bulunamadı diyor. Node.js kurulu değil. Kurun ve terminali yeniden başlatın.
- Inspector açıldı ama Connect hata veriyor. Komut alanında etkin ortamdan python'un belirtildiğinden emin olun. .venv içindeki python.exe'nin tam yolunu yazabilirsiniz.
- Bağlanırken SyntaxError hatası. Kod girintiler kaybolarak kopyalanmış. Python'da girintiler zorunludur: fonksiyon gövdeleri dört boşluk kaydırılır. Dosyayı düzenleyicide kontrol edin.
- Araç 403 hatası döndürüyor. Site isteği kabul etmedi. example.com için bu olmaz, gerçek siteler için proxy adımında buna döneceğiz.
Adım 3: MCP sunucusunu yapay zeka istemcisine bağlıyoruz
Bu aşamanın amacı: sunucuyu yapay zeka istemcisinin ayarlarına kaydetmek, böylece ajan aracınızı görebilsin ve normal sohbetten çağırabilsin. En yaygın seçenek olan Claude Desktop'a bağlanmayı ele alacak ve alternatifleri kısaca göstereceğiz.
Claude Desktop'a bağlantı
- Claude Desktop'ı açın. Ayarlara gidin: Windows'ta sol üstteki menüden Settings; macOS'ta Claude menüsünden Settings.
- Developer sekmesine geçin ve Edit Config düğmesine basın. claude_desktop_config.json dosyasının bulunduğu klasör açılır. Dosya yoksa istemci onu oluşturacaktır.
- Bu dosyanın yedeğini masaüstüne kopyalayarak alın.
- Dosyayı VS Code veya başka bir düzenleyicide açın. Dosya boşsa içeriği tamamen yapıştırın. İçinde başka sunucular varsa kendi bloğunuzu mcpServers nesnesinin içine virgülle ekleyin.
{
"mcpServers": {
"web-collector": {
"command": "C:/mcp-collector/.venv/Scripts/python.exe",
"args": ["C:/mcp-collector/server.py"]
}
}
}macOS ve Linux'ta yolları kendinizinkilerle değiştirin, örneğin /Users/ivan/mcp-collector/.venv/bin/python ve /Users/ivan/mcp-collector/server.py. Dikkat edin: Windows'ta bile yollar düz eğik çizgiyle yazılmıştır. Bu daha kolaydır, çünkü JSON'da ters eğik çizgileri ikiye katlamak gerekir, düz çizgileri ise Windows sorunsuz anlar.
- Dosyayı kaydedin. Son öğeden sonra fazladan virgül olmadığından ve tüm parantezlerin kapalı olduğundan emin olun. Tek bir fazla virgül JSON'u geçersiz kılar ve istemci yapılandırmayı sessizce yok sayar.
- Claude Desktop'ı tamamen kapatın ve yeniden başlatın. Windows'ta pencereyi kapatmak yeterli değildir: sistem tepsisindeki simgeye sağ tıklayıp Quit'i seçin. İstemci yapılandırmayı yalnızca başlangıçta okur.
- Başlattıktan sonra yeni bir sohbet açın. Giriş alanının altında araçlar simgesini (kaydırıcı ya da fiş simgesi) bulun. Tıklayın: listede tek aracı fetch_page olan web-collector sunucusu olmalı.
- Sohbete yazın: "fetch_page kullanarak https://example.com sayfasını indir ve bu sayfanın başlığının ne olduğunu söyle". İstemci araç çağrısı için izin isteyecek. Allow ya da Allow for this chat'e basın.
- Birkaç saniye sonra ajan sayfanın başlığının Example Domain olduğunu söyleyecek. Sunucunuz üzerinden gerçek bir istek yaptı.
Cursor ve VS Code'a bağlantı
Cursor'da Settings, MCP bölümünü açın, Add new global MCP server'a basın. Claude Desktop ile tamamen aynı yapıya sahip mcp.json dosyası açılır. Aynı bloğu yapıştırıp kaydedin. Copilot'lu VS Code'da çalışma klasörünün kökünde .vscode/mcp.json dosyası oluşturun; burada mcpServers anahtarı yerine servers anahtarı kullanılır, içinde aynı command ve args bulunur. Kaydettikten sonra sunucu bloğunun üzerinde Start düğmesi belirir. Tüm istemcilerde mantık aynıdır: yorumlayıcı başlatma komutunu ve betiğin yolunu belirtmek.
İpucu: command alanında sadece python kelimesini değil, sanal ortamdaki python'u belirtin. İstemci süreci kendi ortam değişkenleriyle başlatır ve sistemdeki python komutu kütüphaneleri kurulu olmayan farklı bir sürüm olabilir. Tam yol bu sorunu bir kez ve sonsuza dek ortadan kaldırır.
✅ Kontrol: İstemci arayüzünde web-collector sunucusu görünüyor, ajan istek üzerine fetch_page'i çağırıyor ve example.com sayfasının içeriğini doğru şekilde aktarıyor. İstemci günlüklerinde (Claude Desktop'ta yapılandırmanın yanındaki logs klasöründe, mcp-server-web-collector.log dosyası) fetch_page: https://example.com satırı görünüyor.
Olası sorunlar
- Sunucu listede görünmedi. JSON'un geçerliliğini kontrol edin: içeriği herhangi bir çevrimiçi JSON doğrulayıcıya yapıştırın ya da VS Code'da açın, hataları altını çizecektir. İstemcinin tamamen yeniden başlatıldığından emin olun.
- Sunucunun yanında kırmızı hata göstergesi var. Günlük dosyasını açın. Çoğu zaman orada ModuleNotFoundError vardır: yanlış python belirtilmiş. command içindeki yolu kontrol edin.
- Ajan internete erişemediğini söylüyor. Aracı görmemiş. Kaydırıcı panelinde araçların etkin olduğundan emin olun ve açıkça isteyin: "fetch_page aracını kullan".
- spawn ENOENT hatası. python ya da server.py yolu hatalı belirtilmiş. Yolu gezginden kopyalayın ve ters eğik çizgileri düz çizgiyle değiştirin.
Adım 4: Veri çıkarma araçlarını ekliyoruz
Bu aşamanın amacı: sunucuya ham HTML yerine faydalı veriler döndürmeyi öğretmek: temiz metin, bağlantı listesi ve CSS seçiciyle öğeler. Bundan sonra ajan, bağlamı biçimlendirmeye harcamadan yapılandırılmış bilgi toplayabilecek.
Sadece fetch_page neden yetersiz
Gerçek bir sayfanın HTML'i yüzlerce kilobayt ağırlığındadır ve büyük kısmı betikler, stiller ve servis biçimlendirmesidir. Her seferinde modele her şeyi verirseniz hızla bağlam sınırına dayanır ve fazladan token için ödeme yaparsınız. Doğru strateji: sunucu kaba temizlik ve yapılandırma yapar, model ise zaten kompakt verilerle çalışır. Bu nedenle üç özel araç ekleyeceğiz.
Güncellenmiş kod
server.py içeriğini genişletilmiş sürümle değiştirin. fetch_page fonksiyonu kaldı, ancak genel indirme mantığı tüm araçların kullandığı ayrı bir _get_html fonksiyonuna taşındı.
import sys
from urllib.parse import urljoin
import httpx
from bs4 import BeautifulSoup
from mcp.server.fastmcp import FastMCP
mcp = FastMCP('web-collector')
HEADERS = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0 Safari/537.36',
'Accept-Language': 'ru-RU,ru;q=0.9,en;q=0.8',
}
def log(message: str) -> None:
print(message, file=sys.stderr)
def _get_html(url: str) -> str:
log(f'GET {url}')
with httpx.Client(headers=HEADERS, timeout=20.0, follow_redirects=True) as client:
response = client.get(url)
response.raise_for_status()
return response.text
def _clean(text: str) -> str:
return ' '.join(text.split())
@mcp.tool()
def fetch_page(url: str, max_chars: int = 20000) -> str:
'''Возвращает сырой HTML страницы. Используй только когда нужна именно разметка,
например чтобы подобрать CSS-селектор. Для чтения содержимого используй extract_text.'''
return _get_html(url)[:max_chars]
@mcp.tool()
def extract_text(url: str, max_chars: int = 15000) -> str:
'''Возвращает чистый текст страницы без скриптов, стилей и разметки.
Лучший выбор, когда нужно прочитать статью, описание товара или отзывы.'''
soup = BeautifulSoup(_get_html(url), 'html.parser')
for tag in soup(['script', 'style', 'noscript', 'svg', 'header', 'footer', 'nav']):
tag.decompose()
title = _clean(soup.title.get_text()) if soup.title else ''
body = _clean(soup.get_text(' '))
return f'Заголовок: {title}. Текст: {body}'[:max_chars]
@mcp.tool()
def extract_links(url: str, limit: int = 100, contains: str = '') -> list[dict]:
'''Возвращает список ссылок со страницы: текст ссылки и полный адр��с.
Параметр contains фильтрует ссылки, в адресе которых есть указанная подстрока,
например /product/ или /catalog/.'''
soup = BeautifulSoup(_get_html(url), 'html.parser')
result = []
seen = set()
for a in soup.find_all('a', href=True):
full = urljoin(url, a['href'])
if full in seen or (contains and contains not in full):
continue
seen.add(full)
result.append({'text': _clean(a.get_text())[:120], 'url': full})
if len(result) >= limit:
break
return result
@mcp.tool()
def select_elements(url: str, css_selector: str, limit: int = 50) -> list[str]:
'''Находит на странице элементы по CSS-селектору и возвращает их текст.
Примеры селекторов: h2, .price, div.product-card, table tr.
Используй, когда нужны конкретные повторяющиеся блоки: цены, названия, строки таблицы.'''
soup = BeautifulSoup(_get_html(url), 'html.parser')
elements = soup.select(css_selector)[:limit]
return [_clean(el.get_text(' ')) for el in elements]
if __name__ == '__main__':
mcp.run()Her araç ne yapar
- extract_text belgeden betikleri, stilleri, üst bilgiyi, alt bilgiyi ve menüyü kaldırır, kalan metni tek boşluklarla tek bir satırda birleştirir. _clean fonksiyonu split ve join ile fazladan satır sonlarını ve sekmeleri temizler. Yanıtın başına sayfa başlığı eklenir, böylece ajan önünde ne olduğunu hemen anlar.
- extract_links tüm a etiketlerini toplar, urljoin ile göreli adresleri mutlak adreslere dönüştürür, seen kümesiyle yinelenenleri kaldırır ve bağlantıları alt dizeye göre filtrelemenize olanak tanır. Böylece ajan tek çağrıda örneğin kataloğun tüm ürün kartlarını alır.
- select_elements — en güçlü araç. CSS seçici alır ve bulunan öğelerin metnini döndürür. Ajan önce fetch_page ile HTML'in bir parçasına bakabilir, fiyatların price sınıfında olduğunu anlayabilir ve ardından .price seçicisiyle select_elements'ı çağırabilir.
Docstring'lere dikkat edin: modele hangi durumda hangi aracı seçeceğini açıkça işaret ediyoruz. Bu, ajanın çalışma kalitesini belirgin şekilde artırır.
Nasıl kontrol edilir
- mcp dev server.py komutunu çalıştırın ve Inspector'da bağlanın. Tools listesinde artık dört araç var.
- extract_links'i herhangi bir haber sitesinin veya kataloğun url'siyle ve bölüm adresinin bir kısmına eşit contains parametresiyle çağırın. Sonuç — text ve url alanlarını içeren nesne listesi.
- Aynı adresle ve h2 seçicisiyle select_elements'ı çağırın. Başlıklar listesini alacaksınız.
- Claude Desktop'ı yeniden başlatın (yapılandırmayı değiştirmek gerekmez, sadece kod değişti) ve şunu isteyin: "Şu sitenin ana sayfasından tüm h2 başlıklarını ve haberler bölümüne giden bağlantıları topla ve tablo halinde düzenle".
İpucu: Hangi seçici gerektiğini bilmiyorsanız sayfayı tarayıcıda açın, F12'ye basın, öğe seçme aracını (panelde sol üst köşedeki ok simgesi) seçin ve istediğiniz bloğa tıklayın. Kod içinde sınıfını göreceksiniz. Nokta ve sınıf adından oluşan seçici, örneğin .product-title, genellikle çalışır. Dahası, ajandan basitçe şunu isteyebilirsiniz: "HTML'i indir ve fiyatlar için seçiciyi kendin bul".
✅ Kontrol: Dört aracın tümü Inspector'da ve istemcide görünüyor, extract_text etiketsiz okunabilir metin döndürüyor, extract_links mutlak adresli liste döndürüyor, select_elements h2 seçicisiyle başlıkları döndürüyor.
Olası sorunlar
- select_elements boş liste döndürüyor. Ya seçici yanlış ya da içerik sayfa yüklendikten sonra JavaScript ile geliyor. fetch_page ile kontrol edin: HTML'de gerekli veriler yoksa site bunları istemcide oluşturuyor demektir. Böyle siteler için tarayıcı motoru gerekir, bu ayrı bir makalenin konusu.
- extract_text anlamsız karakterler veriyor. Site standart dışı kodlama döndürüyor. response.raise_for_status() sonrasına response.encoding = response.charset_encoding or 'utf-8' satırını ekleyin.
- Yanıt kesiliyor. Çağrıda max_chars'ı artırın ya da ajandan sayfayı birkaç seçiciyle parça parça istemesini isteyin.
Adım 5: Mobil proxy'leri ve IP rotasyonunu bağlıyoruz
Bu aşamanın amacı: MCP sunucusunun tüm isteklerini mobil proxy üzerinden yönlendirmek, IP değiştirme ve mevcut adresi kontrol etme aracı eklemek. Bundan sonra ajan ev veya ofis IP'nizden değil, bir mobil operatör kimliğiyle çalışacak.
Veri toplayıcı neden mobil proxy'ye ihtiyaç duyar
Tek bir IP adresinden veri topladığınızda siteler arka arkaya düzinelerce aynı isteği görür ve captcha, kısaltılmış içerik ya da 429 "çok fazla istek" hatası vermeye başlar. Mobil proxy aynı anda birkaç sorunu çözer. Birincisi, adres gerçek bir mobil operatöre aittir ve bu tür adresleri binlerce abone paylaşır, bu nedenle siteler onlara daha hoşgörülü davranır. İkincisi, IP'yi bir bağlantıyla veya zamanlayıcıyla değiştirerek yükü dağıtabilirsiniz. Üçüncüsü, ajanın iş etkinliğini kişisel oturumlarınızdan ayırırsınız. Bir pazarlamacı için bu aynı zamanda siteyi belirli bir bölgedeki mobil kullanıcının gördüğü şekilde görme yoludur.
⚠️ Dikkat: Proxy, toplayıcının istikrarlı ve doğru çalışması için bir araçtır, kuralları ihlal etmek için değil. Yalnızca herkese açık verileri toplayın, sitelerin kullanım koşullarına ve robots.txt dosyasına uyun, aşırı yük oluşturmayın ve yasal dayanak olmadan kişisel veri toplamayın. Aracın kullanımına ilişkin sorumluluk size aittir.
Adım adım talimat
- Mobil proxy sağlayıcınızın müşteri panelini açın ve bağlantı verilerini bulun: host, port, kullanıcı adı, şifre. Genellikle login:password@host:port biçiminde tek bir satırda toplanmıştır. Varsa IP değiştirme bağlantısını da oradan kopyalayın.
- server.py dosyasında diğer import'ların ardından en başa import os satırını ekleyin. Ardından HEADERS bloğunun altına ayarları ekleyin:
PROXY_URL = os.environ.get('MOBILE_PROXY_URL', '')
ROTATE_URL = os.environ.get('PROXY_ROTATE_URL', '')
def _client() -> httpx.Client:
kwargs = {'headers': HEADERS, 'timeout': 30.0, 'follow_redirects': True}
if PROXY_URL:
kwargs['proxy'] = PROXY_URL
return httpx.Client(**kwargs)- _get_html fonksiyonunda httpx.Client satırını _client() çağrısıyla değiştirin. Artık şöyle görünür: with _client() as client. Tüm araçlar otomatik olarak proxy üzerinden gider.
- if __name__ satırından önce iki yeni araç ekleyin:
@mcp.tool()
def current_ip() -> str:
'''Показывает IP-адрес, с которого сервер сейчас выходит в интернет.
Используй, чтобы убедиться, что прокси подключён, или после смены IP.'''
with _client() as client:
return client.get('https://api.ipify.org').text.strip()
@mcp.tool()
def rotate_ip() -> str:
'''Запрашивает смену IP-адреса мобильного прокси через ссылку из личного кабинета.
Вызывай, если сайт начал отдавать ошибки 429 или капчу. После вызова подожди 5-10 секунд.'''
if not ROTATE_URL:
return 'Ссылка смены IP не настроена в переменной PROXY_ROTATE_URL'
response = httpx.get(ROTATE_URL, timeout=15.0)
log(f'rotate_ip: status {response.status_code}')
return f'Запрос смены IP отправлен, ответ прокси-сервиса: {response.status_code}'- Proxy verilerini istemci yapılandırmasında ortam değişkenleri üzerinden aktarın. Kullanıcı adı ve şifreyi koda bilerek yazmıyoruz, böylece yanlışlıkla dosyayla birlikte bir yere gönderilmesinler. claude_desktop_config.json dosyasını açın ve sunucu bloğunu env bölümüyle tamamlayın:
{
"mcpServers": {
"web-collector": {
"command": "C:/mcp-collector/.venv/Scripts/python.exe",
"args": ["C:/mcp-collector/server.py"],
"env": {
"MOBILE_PROXY_URL": "http://login:password@proxy-host:port",
"PROXY_ROTATE_URL": "https://ссылка-смены-ip-из-кабинета"
}
}
}
}- login, password, proxy-host ve port yerine gerçek değerleri koyun. Sağlayıcı proxy'yi SOCKS5 protokolüyle veriyorsa http:// yerine socks5:// yazın ve pip install httpx[socks] komutuyla ek paketi kurun.
- Yapılandırmayı kaydedin, istemciyi tamamen yeniden başlatın.
- Ajdandan şunu isteyin: "current_ip'i çağır ve adresimizin ne olduğunu söyle. Sonra rotate_ip'i çağır, on saniye bekle ve IP'yi tekrar kontrol et". Adresler farklı olmalı.
Proxy ile Inspector üzerinden kontrol
Inspector da ortam değişkenlerini aktarabilir. Sol panelde Environment Variables bölümünü açın, kendi değerlerinizle MOBILE_PROXY_URL ve PROXY_ROTATE_URL ekleyin, bağlanın ve current_ip'i çağırın. Yanıt, sağlayıcının panelinde gösterilen IP ile aynı olmalı.
İpucu: Her istekten önce rotate_ip'i çağırmayın. Çoğu sağlayıcıda IP değişimi birkaç saniye sürer ve çok sık istekler değişim limitine takılabilir. Makul strateji: adresi her 30-100 istekte bir ya da yalnızca 429 ve 403 hataları alındığında değiştirmek. Bu mantığı doğrudan _get_html içine gömmek mümkündür, bunu sonraki adımda yapacağız.
✅ Kontrol: current_ip aracı ev adresinizi değil proxy adresini döndürüyor. rotate_ip ve aradan sonra adres değişiyor. extract_text ve extract_links araçları çalışmaya devam ediyor ve günlüklerde sayfa adresleriyle GET satırları görünüyor.
Olası sorunlar
- 407 Proxy Authentication Required hatası. Kullanıcı adı veya şifre yanlış ya da içlerinde özel karakter var. Şifredeki @ veya : gibi karakterler kodlanmalıdır: @ yerine %40, : yerine %3A.
- ConnectTimeout hatası. Host veya port yanlış ya da tarifenizde böyle bir bağlama varsa IP'niz sağlayıcı panelindeki izin verilenler listesine eklenmemiş.
- current_ip kendi adresinizi gösteriyor. Ortam değişkeni sunucuya ulaşmadı. Yapılandırmadaki MOBILE_PROXY_URL yazımını kontrol edin ve istemcinin yeniden başlatıldığından emin olun.
- rotate_ip 429 durumu veya limit mesajı döndürüyor. IP'yi tarifenin izin verdiğinden daha sık değiştiriyorsunuz. Aralığı artırın.
Adım 6: Sunucuyu güvenilir hale getiriyoruz: yeniden denemeler, gecikmeler, önbellek ve limitler
Bu aşamanın amacı: eğitim örneğini ilk ağ hatasında çökmeyen, sitelere istek yağdırmayan ve modelin bağlamını taşırmayan bir araca dönüştürmek. Bu, tam kullanımdan önceki son zorunlu adımdır.
Neyi ve neden ekliyoruz
- Otomatik yeniden denemeler. Ağ hataları olur. Ajana hemen hata döndürmek yerine isteği arada bekleyerek iki kez daha deneyeceğiz.
- Engellemede otomatik IP değişimi. Site 429 veya 403 yanıtlarsa ve rotasyon bağlantısı ayarlıysa sunucu kendisi adresi değiştirip isteği yineler.
- İstekler arası gecikme. Kibar bir toplayıcı saniyede düzinelerce istek göndermez. Bir-iki saniyelik duraklama site üzerindeki yükü ve engellenme riskini azaltır.
- Önbellek. Ajan genellikle aynı sayfayı farklı araçlarla birkaç kez ister. Birkaç dakikalık belleğ içi önbellek tekrarlı indirmeleri önler.
- Boyut limiti. Birkaç megabayttan ağır sayfaları indirmeyeceğiz.
Kod
Dosyanın başına import time ekleyin ve _get_html fonksiyonunu şununla değiştirin:
CACHE: dict[str, tuple[float, str]] = {}
CACHE_TTL = 300
REQUEST_DELAY = 1.5
MAX_BYTES = 3_000_000
_last_request = 0.0
def _get_html(url: str) -> str:
global _last_request
now = time.time()
cached = CACHE.get(url)
if cached and now - cached[0] < CACHE_TTL:
log(f'cache hit: {url}')
return cached[1]
last_error = None
for attempt in range(3):
wait = REQUEST_DELAY - (time.time() - _last_request)
if wait > 0:
time.sleep(wait)
try:
with _client() as client:
_last_request = time.time()
response = client.get(url)
if response.status_code in (403, 429) and ROTATE_URL:
log(f'status {response.status_code}, rotating ip')
httpx.get(ROTATE_URL, timeout=15.0)
time.sleep(8)
continue
response.raise_for_status()
if len(response.content) > MAX_BYTES:
raise ValueError(f'Страница слишком большая: {len(response.content)} байт')
html = response.text
CACHE[url] = (time.time(), html)
return html
except httpx.HTTPError as error:
last_error = error
log(f'attempt {attempt + 1} failed: {error}')
time.sleep(2 * (attempt + 1))
raise RuntimeError(f'Не удалось загрузить {url} после 3 попыток: {last_error}')Nasıl çalışır
- CACHE sözlüğü her adres için indirme zamanını ve HTML'i saklar. Sayfa beş dakikadan kısa süre önce istendiyse istek yapmadan kayıtlı kopyayı döndürürüz.
- Her istekten önce bir öncekinden ne kadar geçtiğini hesaplar ve gerekirse REQUEST_DELAY saniyeye kadar duraklama ekleriz.
- Üç denemeli döngü. 403 veya 429 yanıtında ve rotasyon ayarlıysa sunucu IP'yi değiştirir, sekiz saniye bekler ve tekrar dener. Ağ hatalarında denemeler arasında iki, dört, altı saniye bekler.
- Sayfa üç megabayttan büyükse bunu hata sayarız: bu tür belgeler bağlama zaten sığmaz.
- Üç başarısız denemeden sonra adres ve nedeni içeren anlaşılır bir hata fırlatırız. Ajan bunu metin olarak alır ve size bildirebilir ya da başka bir yol deneyebilir.
Ayrıca ajanın sayfayı zorla yeniden yükleyebilmesi için önbelleği temizleme aracı eklemenizi öneririz:
@mcp.tool()
def clear_cache() -> str:
'''Очищает кэш загруженных страниц. Вызывай, если нужно получить свежую версию страницы.'''
count = len(CACHE)
CACHE.clear()
return f'Кэш очищен, удалено записей: {count}'İpucu: REQUEST_DELAY ve CACHE_TTL değerlerini proxy'de olduğu gibi ortam değişkenlerine taşımak, kodu düzenlemeden değiştirmenizi sağlar. Fiyat izleme için iki-üç saniyelik gecikme ve bir dakikalık önbellek, makale toplama için bir saniyelik gecikme ve bir saatlik önbellek uygundur.
✅ Kontrol: Aynı sayfa için extract_text'i arka arkaya iki kez çağırın. İkincisinde günlüklerde cache hit satırı görünecek ve yanıt anında gelecek. Var olmayan bir alan adı belirtin — birkaç saniye sonra ajan "Не удалось загрузить... после 3 попыток" mesajı alacak, takılı kalmayacak.
Olası sorunlar
- NameError: ROTATE_URL tanımlı değil. _get_html fonksiyonu proxy ayarları bloğunun üstünde tanımlanmış. PROXY_URL ve ROTATE_URL ayarlarını dosyada yukarı taşıyın.
- Ajan yavaş çalışmadan şikayet ediyor. Bu normaldir: gecikmeler ve IP rotasyonu zaman alır. Acele ediyorsanız REQUEST_DELAY'i 0.5'e düşürün, ama engellenme riskini unutmayın.
- Bellek büyüyor. Önbellek oturum boyunca tüm sayfaları saklar. Uzun oturumlar için her çağrıda TTL'den eski kayıtları temizleyin ya da sözlük boyutunu sınırlayın.
Sonucu kontrol etme: hazır MCP sunucusu için kontrol listesi
Kontrol listesini gözden geçirin ve her maddeyi işaretleyin. Hepsi yerine getiriliyorsa veri toplama MCP sunucunuz gerçek iş için hazırdır.
Çalışması gerekenler
- mcp dev server.py komutu hatasız başlıyor, Inspector bağlanıyor ve Connected durumunu gösteriyor.
- Araç listesinde fetch_page, extract_text, extract_links, select_elements, current_ip, rotate_ip ve clear_cache var.
- web-collector sunucusu yapay zeka istemcisinin araçlar panelinde hata göstergesi olmadan görünüyor.
- Ajan serbest biçimli bir istek üzerine uygun aracı kendisi seçiyor ve çağırıyor.
- current_ip mobil proxy adresini gösteriyor ve rotate_ip sonrası adres değişiyor.
- Aynı sayfanın tekrarlı isteği önbellekten veriliyor.
- Hatalı adres takılmaya değil, anlaşılır bir hata mesajına yol açıyor.
Kapsamlı test
- Verilerinin kullanılmasına izin verilen, kataloğu veya makale akışı olan herkese açık bir site seçin.
- Ajdandan şunu isteyin: "Sitenin ana sayfasını aç, katalog bölümüne giden bağlantıları bul, ilk beş karta gir, adı ve fiyatı topla ve Ad, Fiyat, Bağlantı sütunlarıyla tablo halinde düzenle".
- Çağrı zincirini izleyin: ajan filtreli extract_links'i, ardından birkaç kez select_elements veya extract_text'i çağırmalı ve sonunda tabloyu oluşturmalı.
- Kartları tarayıcıda açarak birkaç satırı elle kontrol edin. Veriler eşleşmelidir.
Başarı göstergeleri
Beş kartın toplanması gecikmeler dahil en fazla 30-40 saniye sürer. İstemci günlüklerinde traceback düzeyinde hata yoktur. Ajan hangi aracı kullanacağını tekrar sormaz, kendisi hareket eder. Her şey böyleyse tebrikler: kendi MCP sunucunuzu kurdunuz ve yapay zeka ajanını web'e bağladınız.
MCP sunucusu oluştururken sık yapılan hatalar ve çözümleri
Burada neredeyse herkesin ilk geçişte karşılaştığı sorunlar toplanmıştır. Biçim: sorun, neden, çözüm.
1. Sunucu Inspector'da bağlanıyor ama istemcide çalışmıyor
Neden: istemci yapılandırmasında kütüphaneleri kurulu olmayan sistem python'u ya da yanlış dosya yolu belirtilmiş. Çözüm: .venv içindeki python'un tam yolunu ve server.py'nin tam yolunu yazın, düz eğik çizgi kullanın, istemciyi tamamen yeniden başlatın.
2. İstemci başlatmadan hemen sonra bağlantıyı kesiyor
Neden: kodda file=sys.stderr olmadan normal print kalmış ve servis stdout akışı kirlenmiş. Çözüm: tüm print'leri log fonksiyonuyla değiştirin. Kütüphanelerin de stdout'a yazmadığını kontrol edin: örneğin bazı ilerleme çubukları varsayılan olarak bunu yapar.
3. Ajan araçları çağırmıyor ve kendi bilgisinden yanıtlıyor
Neden: araç açıklamaları çok kısa veya belirsiz ve model ne zaman uygulayacağını anlamıyor. Çözüm: docstring'leri genişletin, "şu durumda kullan..." ifadeleri ve örnekler ekleyin. İlk isteklerde aracı açıkça adlandırın.
4. Gerçek siteleri yüklerken 403 hatası
Neden: site tarayıcı başlıkları olmadan veya şüpheli bir IP'den gelen istekleri kabul etmiyor. Çözüm: HEADERS'ın aktarıldığını kontrol edin, User-Agent'ı güncel tarayıcı sürümüne güncelleyin, mobil proxy bağlayın ve rotasyonun çalıştığından emin olun.
5. Doğru seçiciye rağmen select_elements boş sonuç veriyor
Neden: veriler sayfa yüklendikten sonra JavaScript ile geliyor ve kaynak HTML'de yok. Çözüm: fetch_page ile kontrol edin. Veri yoksa tarayıcının Network sekmesinde sitenin iç API'sini bulmayı deneyin: kartlar genellikle ayrı bir adresten JSON olarak gelir ve aynı extract_text ile doğrudan istenebilir.
6. Proxy üzerinden çalışırken 407 veya ConnectTimeout hatası
Neden: yanlış kimlik bilgileri, şifrede kodlanmamış özel karakterler veya yanlış port. Çözüm: bağlantı dizesini panelden yeniden kopyalayın, özel karakterleri kodlayın, http veya socks5 protokolünü kontrol edin.
7. JSON yapılandırması uygulanmıyor
Neden: fazladan virgül, eksik tırnak veya yollarda ters eğik çizgi. Çözüm: dosyayı doğrulayıcıda kontrol edin, ters eğik çizgileri düz eğik çizgiyle değiştirin, son öğeden sonra virgül olmadığından emin olun.
8. Sunucu çalışıyor ama veriler yanlış kodlamada geliyor
Neden: site başlıklarda kodlama belirtmiyor. Çözüm: response.encoding'i açıkça ayarlayın ya da response.content özniteliğini decode('utf-8', errors='ignore') ile elle çözerek kullanın.
Ek olanaklar: ileri düzeyler için bölüm
Temel sunucu hazır. Python'u güvenle yazıyorsanız ve daha fazlasını istiyorsanız, her biri bir akşamda hayata geçirilebilecek gelişim yönleri şunlar.
Streamable HTTP üzerinden uzak sunucu
Sunucunun ayrı bir makinede çalışması veya birkaç istemcinin bağlanması için son satırı mcp.run(transport='streamable-http') ile değiştirin. Sunucu varsayılan olarak 8000 portunda ayağa kalkar ve bağlantı adresi http://makine-adresi:8000/mcp olur. İstemci yapılandırmasında command ve args yerine bu adresle url anahtarını belirtin. Bu modda stdout'a yazmak mümkündür, ama stderr'e günlük yazma alışkanlığını korumak daha iyidir. Portu mutlaka dış dünyaya kapatın ve sunucu yalnızca yerel ağdan erişilebilir değilse başlıkta token doğrulaması ekleyin.
Kaynaklar ve istemler
Mevcut ayarlarla bir kaynak, ajanın çalışma bağlamını anlamasına yardımcı olur:
@mcp.resource('collector://settings')
def settings() -> str:
'''Текущие настройки сборщика.'''
return f'proxy: {"on" if PROXY_URL else "off"}, delay: {REQUEST_DELAY}, cache ttl: {CACHE_TTL}'Bir istem, kullanıcının tek komutla çağırdığı hazır bir senaryo tanımlar:
@mcp.prompt()
def price_monitor(url: str) -> str:
'''Сценарий мониторинга цен в каталоге.'''
return f'Открой {url}, собери ссылки на карточки товаров, зайди в каждую, вытащи название и цену и составь таблицу. Если увидишь ошибку 429, вызови rotate_ip и продолжи.'Sonuçları dosyaya kaydetme
Sözlük listesi ve dosya yolu alan, verileri csv modülü üzerinden yazan save_csv aracını ekleyin. Ajan yalnızca toplamakla kalmaz, sonuçları Excel'de açacağınız bir tabloya da dökebilir. Kaydetme yolunu tek bir klasörle sınırlayın ki ajan diskte herhangi bir yere yazamasın.
Asenkronluk ve paralel toplama
FastMCP asenkron fonksiyonları destekler: aracı async def ile tanımlayın ve httpx.AsyncClient kullanın. Böylece fetch_many aracı asyncio.gather üzerinden on sayfayı aynı anda yükleyebilir. Paralel istek sayısını sınırlayan semaforu ve paralellikte istekler arası gecikmenin farklı hesaplanması gerektiğini unutmayın.
Birden fazla proxy ve akıllı rotasyon
Farklı bölgeler için birkaç mobil proxy'niz varsa bunları virgülle ayrılmış liste olarak bir ortam değişkeninde saklayın ve araca region parametresi ekleyin. Sunucu proxy'yi bölgeye göre seçer, ajan ise sitenin farklı şehirlerdeki kullanıcılara gösterdiği fiyatları karşılaştırabilir. Bu, pazarlamacılar ve arbitrajcılar arasında en çok talep gören görevlerden biridir.
Docker'a paketleme
Sunucuda çalıştırmak için python:3.12-slim tabanlı bir imaj oluşturun, server.py'yi ve bağımlılık dosyasını kopyalayın, paketleri kurun ve HTTP taşımalı giriş noktasını belirtin. Proxy değişkenlerini imaja gömmek yerine konteyner başlatılırken aktarın.
⚠️ Dikkat: Kullanıcı adları, şifreler ve rotasyon bağlantıları içeren kodu asla açık depolarda yayınlamayın. Bunları yalnızca ortam değişkenlerinde ya da .gitignore'a eklenmiş bir .env dosyasında tutun. IP değiştirme bağlantısının sızması, başkalarının proxy'nizi yönetmesine olanak tanır.
SSS: MCP sunucusu oluşturma hakkında sık sorulan sorular
MCP sunucusu Python dışında bir dilde yazılabilir mi?
Evet. TypeScript, Java, Kotlin, C# ve diğer diller için resmi SDK'lar var. İlkeler aynıdır: açıklamalı araçlar tanımlamak ve taşımayı başlatmak. Python, basitliği ve HTML ile çalışmak için zengin kütüphane seti nedeniyle rehberde seçildi.
MCP ile çalışmak için ücretli yapay zeka istemcisi gerekli mi?
Claude Desktop yerel MCP sunucularını ücretsiz planda da destekler, ancak mesaj sayısında limitler vardır. Cursor ve VS Code da sunucu bağlamaya izin verir. Güncel koşulları ilgili istemciden kontrol edin.
Proxy kullanmak zorunlu mu?
Hayır, sunucu doğrudan da çalışır. Proxy, istek hacmi belirgin olduğunda, siteler istek sıklığına duyarlıysa ya da içeriği belirli bir bölgeden ve mobil IP'den görmeniz önemliyse gereklidir.
İsteklerin gerçekten proxy üzerinden gittiğini nasıl anlarım?
current_ip aracını çağırın ve adresi sağlayıcı panelinin gösterdiğiyle karşılaştırın. Ek olarak ajandan bir IP belirleme servisinin sayfasını extract_text ile yüklemesini isteyebilirsiniz.
Bir sunucuya kaç araç eklenebilir?
Teknik olarak neredeyse sınır yoktur, ancak her açıklama modelin bağlamında yer kaplar. Pratikte iyi açıklanmış 5-15 araç, 50 küçükten daha iyi çalışır. Yakın fonksiyonları parametrelerle gruplayın.
İstemciyi yeniden başlatmadan sunucu nasıl güncellenir?
stdio taşımasında istemci süreci başlangıçta başlattığı için kod değişiklikleri ancak istemci yeniden başlatıldıktan sonra alınır. Geliştirme sırasında düzeltmeleri Inspector üzerinden kontrol etmek, istemciyi ise bitince yeniden başlatmak daha uygundur.
Site verileri yalnızca JavaScript çalıştırıldıktan sonra veriyorsa ne yapmalı?
Sunucumuz kaynak HTML ile çalışır ve bu tür verileri görmez. Seçenekler: tarayıcının Network sekmesinde sitenin iç API'sini bulmak ya da bir tarayıcı motoru bağlamak. İkinci yol blogdaki ayrı içeriklerde anlatılmıştır, burada bilinçli olarak değinmiyoruz.
Ajanı istenmeyen sitelere gitmemesi için nasıl sınırlarım?
_get_html içine ortam değişkeninden beyaz veya kara listeye göre alan adı kontrolü ekleyin ve yasak adresler için anlaşılır hata döndürün. Bu, sohbetteki talimatlara güvenmekten daha güvenilirdir.
Aynı MCP sunucusu birkaç istemciden aynı anda kullanılabilir mi?
stdio'da her istemci kendi süreç kopyasını başlatır ve bu normaldir: birbirlerine engel olmazlar, ancak önbellekleri ayrıdır. Ortak önbellek ve tek proxy için ileri düzey bölümdeki HTTP taşımasına geçin.
Sonuç: ne yaptınız ve bundan sonra nereye
Özetleyelim. Python ortamını hazırladınız ve protokolün resmi SDK'sını kurdunuz. MCP sunucusunu sıfırdan yazdınız ve modelin araçları açıklamaları üzerinden nasıl anladığını çözdünüz. Sunucuyu yapay zeka istemcisine bağladınız ve ajanın sayfaları kendisinin yüklediğini gördünüz. Metin, bağlantı ve seçiciyle öğe çıkarma araçlarını eklediniz. Trafiği IP rotasyonlu mobil proxy üzerinden yönlendirdiniz. Son olarak sunucuyu dayanıklı hale getirdiniz: yeniden denemeler, gecikmeler, önbellek ve limitler. Bu artık eğitim örneği değil, günlük görevler için çalışan bir araç.
Bundan sonra ne yapmalı? Sunucuyu gerçek senaryolarda kullanmaya başlayın: rakip fiyatlarını izleme, yorum toplama, açılış sayfalarını kontrol etme, niş içeriği analiz etme. Süreçte tam olarak hangi araçların eksik olduğunu anlayacak ve mevcutları örnek alarak ekleyeceksiniz. Her yeni araç, açıklaması net bir fonksiyondur, daha karmaşık bir şey değil.
Sonraki seviye ileri düzey bölüm: HTTP üzerinden uzak sunucu, paralel toplama, bölgelere göre birden fazla proxy ile çalışma ve sonuçları tablolara kaydetme. Dinamik içerikli sitelere takıldığınızda ise blogun tarayıcı otomasyonuyla ilgili yan makalelerine göz atın. En önemlisini zaten yaptınız: yapay zeka ajanınız kendi MCP sunucunuz üzerinden web'e çıktı ve bunu nasıl yaptığını tamamen siz kontrol ediyorsunuz.