← Back to list

MCP’yi Korkmadan Öğrenin: Agent’larla Adım Adım Kendi Sisteminizi Kurun

Kavramdan koda: MCP nedir, nasıl çalışır ve nasıl yazılır?

Gunal Hincal · 2026-05-19 22:02 · 0 claps · 23.2 min read paywalled
#artificial-intelligence #machine-learning #mcp-server #ai-agent #generative-ai-tools
Open on Medium ↗
Wiki topics: AGT · AI Agents ML · Machine Learning AI · AI · General EDU · Education & Learning 🎮 · Gaming

MCP’yi Korkmadan Öğrenin: Agent’larla Adım Adım Kendi Sisteminizi Kurun

Kavramdan koda: MCP nedir, nasıl çalışır ve nasıl yazılır?

Created by the author — MCP as the connection layer between agents, models, and external systems

Created by the author — MCP as the connection layer between agents, models, and external systems

Bu yazı, Model Context Protocol (MCP) ve Agent mimarisini sıfırdan öğrenmek isteyenler için hazırlanmış pratik bir rehberdir. Kavramları sade bir dille açıklayıp, çalışan kod örnekleriyle kendi Agent ve MCP sistemimizi adım adım inşa edeceğiz. Karmaşık terimlerle değil, örneklerle, analojilerle ve çalışan kodlarla ilerleyeceğiz.

Yazıya başlamadan birkaç şey söylemek istiyorum. Bu yazı aslında uzun zamandır içimde duran bir yazıydı. Yaklaşık bir yıl önce MCP ve Agent mimarisi hakkında yazmaya niyetlenmiştim. Sonra altı ay önce tekrar dosyayı açıp “tamam, bu sefer bitireceğim” dedim. Ama konunun kısa bir yazıyla geçiştirilecek kadar basit olmadığını biliyordum. Üstelik ben yazıyı erteledikçe yapay zekâ dünyası da durmadı; modeller gelişti, yeni araçlar çıktı, agent framework’leri çoğaldı ve MCP çok daha görünür bir konu haline geldi. Dolayısıyla başta birkaç temel kavramı anlatmak için düşündüğüm bu içerik, zamanla daha kapsamlı bir rehbere dönüştü. Bu yazıda bu yüzden sadece “MCP nedir?” demeyeceğiz; Agent mantığını anlayacak, çalışan örnekler yazacak ve en sonunda bu yapının gerçek MCP protokolüne nasıl bağlandığını göreceğiz.

Medium üyesiyseniz yazıyı buradan okumaya devam edebilirsiniz. Üye değilseniz endişelenmeyin; yazının tamamını okumak için buraya tıklayabilirsiniz.

🎯 Bu Yazıda Neler Öğreneceksiniz?

Bu yazıda üç ana bölüm üzerinden ilerleyeceğiz:

1. Bölüm: MCP ve Agent nedir? Aralarındaki fark ne? 2. Bölüm: Python ile basit ve orta seviye agent örnekleri 3. Bölüm: Flask ile MCP mantığını simüle etmek ve gerçek MCP’ye dönüştürmek

Böylece önce kavramları zihnimizde netleştirecek, ardından çalışan örneklerle agent mantığını kuracak ve son olarak MCP’nin bu yapıya nasıl bağlandığını adım adım göreceğiz.

Bu yazının sonunda sadece bir yazı okumuş olmayacaksınız, aynı zamanda adım adım bir MCP sistemi de kurmuş olacaksınız.

  • MCP ve Agent kavramlarını hem teknik hem de günlük hayat örnekleri ile anlamış olacaksınız
  • İkisi arasındaki kritik farkları mimari düzeyde kavrayacak ve ilişkilerini net biçimde görebileceksiniz
  • Gerçek Python kodlarıyla bir Agent kurabileceksiniz
  • Bir Agent’ın neler yapabildiğini, MCP’nin bu Agent’lara nasıl güç kattığını kavramış olacaksınız
  • MCP kullanarak harici verilere bağlanabiliyor olacaksınız
  • Sonraki bölümlerde yazacağımız kodları zihninizde nereye oturtmanız gerektiğini biliyor olacaksınız
  • Ve en sonunda kendi mini asistanınızı çalıştırabiliyor olacaksınız

Sonunda, artık “MCP nedir?” diye aratmanıza gerek kalmayacak. Çünkü siz zaten kendi MCP’nizi yazmış olacaksınız. 💪

Hiçbir ek bilgiye gerek yok. Sadece Python bilmeniz yeterli. Bilmiyorsanız da üzülmeyin; “Vibe Coding” denen yaklaşımla, inşa etmek istediğimiz sistemi bir yapay zekâ modeli ile yazışarak çalışan bir sistem haline getirebileceğiz.

Hadi şimdi temelden başlayalım.

📚 Bölüm 1: Temelleri Anlayalım

🔌 MCP Nedir?

MCP, Anthropic tarafından geliştirilen ve Kasım 2024'te açık kaynak olarak duyurulan bir protokoldür. Temel amacı, yapay zeka modellerinin farklı araçlar, servisler ve veri kaynaklarıyla standart bir şekilde iletişim kurmasını sağlamaktır.

MCP yeni sayılabilecek bir kavram olmasına rağmen, bu kavramı yeterince netleştirememiş çok sayıda teknik ve teknik olmayan kişiyle karşılaştım. Bu yazının ilhamı da tam olarak buradan doğdu.

MCP’leri daha anlaşılır, sade ve herkesin erişebileceği bir biçimde anlatmak istedim; hem yazılım geliştiriciler hem de yapay zekâ meraklıları için, Zero to Hero yaklaşımıyla ilerleyen bir içerik hazırladım.

Amacım, karmaşık görünen bu protokolü herkesin anlayabileceği örneklerle açıklamak ve MCP’yi “henüz göz atılmamış bir teknoloji” olmaktan çıkarıp, kendi başına inşa edilebilen bir araç haline getirmektir.

MCP, yapay zekâ modellerinin harici veri kaynaklarıyla güvenli ve standart bir biçimde iletişim kurmasını sağlayan bir protokoldür.

Yani bir yapay zekâ modelinin Google Drive’daki bir belgeye erişebilmesi, Slack mesajlarını analiz edebilmesi ya da SQL veri tabanıyla etkileşime geçebilmesi MCP sayesinde gerçekleşmektedir.

MCP, modellerin yalnızca yanıt üreten sistemler olmaktan çıkıp, dünyayla etkileşim kurabilen akıllı ajanlara dönüşmesini sağlayan yapıdır.

Teknik açıdan MCP şunları sağlamaktadır:

  • Model ile dış dünya arasında standart bir mesajlaşma formatı
  • Dosya sistemleri, API’ler, veri tabanları, üçüncü parti uygulamalar gibi farklı kaynaklara aynı dilden erişim
  • Modüler ve yeniden kullanılabilir “sunucular” üzerinden entegrasyon
  • Güvenli ve kontrollü bir erişim katmanı

Kısaca, modelin kendi başına göremediği veri kaynaklarına, tutarlı ve yönetilebilir bir yolla ulaşmasını sağlayan altyapıdır.

Basit bir örnek verecek olursak

Evdeki elektrik prizlerini düşünün. Televizyon, bilgisayar, telefon şarjı, süpürge; hepsi farklı cihazlardır. Buna rağmen hepsi aynı priz tipine takılabilmektedir.

Bu priz standardı sayesinde:

  • Her cihaz için ayrı bir elektrik sistemi kurmanız gerekmez.
  • Farklı markalar ve cihazlar, aynı altyapıyı kullanabilmektedir.
  • Yeni aldığınız bir cihazı, evinizdeki mevcut sisteme kolayca entegre edersiniz.

MCP de benzer şekilde çalışmaktadır. Farklı veri kaynakları, örneğin; Google Drive, Slack, Postgres, HTTP API vb. gibi, hepsi kendi MCP sunucularına sahiptir. Model, MCP sunucusunun sunduğu araçları ve kaynakları görür. Kullanıcı dosya okuma, veri tabanı sorgulama veya API çağırma gibi bir ihtiyaç belirttiğinde agent uygun aracı seçer; MCP sunucusu da bu araca güvenli ve standart biçimde erişim sağlar.

MCP’nin Sağladığı Başlıca Faydalar:

🔄 Tek bir protokol ile çok sayıda kaynağa bağlanma imkânı Farklı entegrasyonlar için ayrı ayrı karmaşık kodlar yazma ihtiyacını azaltmaktadır.

🔐 Güvenli ve kontrollü erişim Hangi dizinlerin, hangi veri tabanlarının ya da hangi API’lerin görünebilir olduğu protokol seviyesinde belirlenebilmektedir.

🚀 Hızlı entegrasyon Hazır MCP sunucuları sayesinde projeye yeni bir kaynak eklemek çok daha kolay hale gelmektedir.

🌍 Açık ve genişleyebilir standart Farklı modeller ve araçlar MCP etrafında birleşebildiği için ekosistem büyüdükçe sizin kodlarınız geçerliliğini korumaktadır.

🤖 Agent Nedir?

Agent kavramı, yapay zekâ ekosisteminde en az MCP kadar önemli bir yere sahiptir. Basitçe söylemek gerekirse, bir Agent (Yapay Zekâ Ajanı), kendisine verilen bir görevi adım adım yerine getirebilen, gerektiğinde karar verebilen ve farklı araçları kullanarak hedefe ulaşabilen otonom bir sistemdir. Yapay zekânın karar verme, planlama ve otomasyon yeteneklerini genişletmek için tasarlanmıştır.

Büyük dil modelleri (örneğin ChatGPT, Claude, Gemini gibi) çok güçlü bilgi üreticileridir; ancak tek başına çalıştıklarında dış dünyayla etkileşime geçemezler. Bir Agent bu noktada devreye girmektedir: modelin kararlarını gerçek sistemlerde uygulayan, sonuçları izleyen ve gerekirse yeniden planlama yapan yürütücü bir zekâ katmanıdır.

Teknik olarak bir Agent şunları yapabilmektedir:

  • Görev veya amaç alır
  • Bu amacı gerçekleştirmek için gerekli adımları planlar
  • Harici araçlarla (API, veri tabanı, MCP sunucuları vb.) etkileşime girer
  • Elde ettiği verileri analiz eder ve sonraki adımını buna göre günceller
  • Sonuçları derler, değerlendirir ve size nihai çıktı olarak sunar

Basit bir örnek verecek olursak

Bir asistanınız olduğunu düşünün. Ona şöyle diyorsunuz:

“Yarınki toplantı için katılımcı listesini hazırla, herkese davet maili gönder, ardından takvime ekle.”

Asistan ne yapmaktadır?

  • Katılımcı listesini bulur
  • Mail adreslerini kontrol eder
  • Takvim sistemine bağlanır
  • Uygun saatleri karşılaştırır
  • Odaları kontrol eder, müsait değilse alternatif arar
  • Maili yazar, gönderir
  • Sonuçta size dönüp “Toplantı planlandı.” der

İşte bir AI Agent da aynı şekilde çalışmaktadır. Siz yalnızca “yarınki toplantıyı ayarla” diyorsunuz, o ise arka planda tüm bu adımları planlıyor, uyguluyor ve size sonucu sunuyor.

Agent’lar genellikle bu üç ana bileşenden oluşmaktadır:

  1. Planner (Planlayıcı): Görevi alt adımlara böler, neyin ne zaman yapılacağını belirler.
  2. Executor (Yürütücü): Belirlenen adımları sırasıyla çalıştırır, gerekli araçları kullanır.
  3. Memory (Bellek): Önceki işlemlerin sonuçlarını ve öğrenilen bilgileri kaydeder.

Bu üç bileşen; Planner, Executor ve Memory bir araya geldiğinde, Agent artık yalnızca cevap üreten bir sistem değil, kendi kararlarını uygulayabilen bir dijital çalışana dönüşmektedir.

Agent’ın Temel Özellikleri

Otonomdur. Görevi aldıktan sonra sürekli kullanıcı müdahalesine gerek duymadan çalışmaktadır.

Planlama yapabilmektedir. Verilen bir hedefi mantıksal adımlara ayırır, sıraya koyar ve yürütür. Bu planlama katmanına Planner (Planlayıcı) denir.

Araçları kullanmaktadır. API’ler, veri tabanları, dosya sistemleri veya MCP sunucuları gibi kaynaklara bağlanarak veri çekebilir ya da işlem başlatabilir. Bu katmana Executor (Yürütücü) denir.

Karar verebilmektedir. Bir adım başarısız olduğunda alternatif çözüm üretebilir, tekrar deneyebilir veya süreci yeniden yapılandırabilir.

Öğrenmeye açıktır. Bazı gelişmiş Agent sistemleri geçmiş etkileşimleri bellekte tutarak benzer görevlerde daha bağlamsal ve tutarlı davranabilir.

Neden Önemlidir?

Agent’lar, yapay zekâyı pasif bir bilgi kaynağı olmaktan çıkarıp, aktif bir problem çözücü ve görev yürütücüye dönüştürmektedir.

Bu sayede:

  • Veri analizi, müşteri desteği, raporlama, içerik üretimi, süreç yönetimi gibi görevler otonom hale gelmektedir
  • İnsan müdahalesi minimuma inerken hız ve doğruluk artmaktadır
  • En önemlisi, yapay zekâ artık yalnızca konuşan değil, harekete geçebilen bir sisteme dönüşmektedir.

⚡ Agent vs MCP: Fark Nedir?

Artık hem Agent’ı hem de MCP’yi ayrı ayrı tanıdık. Şimdi sıra geldi bu iki kavram arasındaki farkı net biçimde anlamaya. En sade haliyle şöyle düşünebiliriz:

**Agent işi yapan zekâdır,**

**MCP ise o zekânın dünyayla iletişim kurmasını sağlayan köprüdür.**

Yani bir Agent bir görevi planlar, analiz eder ve hangi araçları kullanması gerektiğine karar verir. MCP ise o araçlara giden kapıyı açar; dosya sistemine, API’ye, veri tabanına veya bir servise güvenli biçimde bağlanmasını sağlar.

Teknik olarak bakarsak:

  • Agent, bir işçidir. Görevi planlar, adımlara böler, uygular; “ne yapılacağına” karar verir.
  • MCP ise o işçinin kullandığı araçlara erişim kapısıdır. “Nasıl erişileceğini” belirler. Agent, MCP sayesinde o araçlarla konuşur, bilgi alır ve işini tamamlar.

Yani MCP, Agent’ın eylemlerini destekleyen görünmez altyapıdır.

Bu farkı daha net görmek için Agent ve MCP’yi yan yana düşünelim:

Created by the author — A simple comparison of Agent and MCP roles in an AI system

Created by the author — A simple comparison of Agent and MCP roles in an AI system

💻 Bölüm 2: Pratik Yapma Zamanı - Hadi İlk Agent’ımızı Yazalım

🎓 Örnek 1: Basit Bir Agent - Hava Durumu Öneri Asistanı

Şimdi teoriden biraz uzaklaşıp, çok basit bir agent örneği yazalım.

Bu örnekte amacımız gelişmiş, çok araçlı, hafızalı ve tamamen otonom bir agent geliştirmek değil. Buradaki hedefimiz, agent mantığını en sade haliyle anlamak. Yani bu örnek bize şunu gösterecek:

Bir sistem nasıl kullanıcıdan bir hedef alır, dış bir kaynaktan veri çeker, gelen veriyi yorumlar, basit bir karar verir ve kullanıcıya aksiyon önerisi üretir?

Senaryomuz şu:

Hava durumunu kontrol eden ve yağmur varsa kullanıcıya şemsiye almasını hatırlatan basit bir hava durumu agent’ı geliştireceğiz. Bu agent, OpenWeatherMap API’yi bir araç gibi kullanacak. Kullanıcıdan şehir bilgisini alacak, hava durumunu sorgulayacak, gelen veriyi analiz edecek ve hava durumuna göre kullanıcıya öneri sunacak.

Önemli not: Bu örnek, tam anlamıyla otonom ve gelişmiş bir agent değildir. Kendi kendine karmaşık planlar yapan, birden fazla araç arasında seçim yapan veya geçmişini hatırlayan bir yapı değildir. Ama agent davranışının temel iskeletini gösterir: bir hedef, bir araç, bir analiz adımı ve bir öneri.

Daha sonraki örneklerde bu yapıyı geliştirerek doğal dil anlayan, farklı araçlara bağlanan, planlama yapan ve MCP üzerinden dış sistemlerle haberleşebilen daha güçlü agent mimarilerine doğru ilerleyeceğiz.

📋 Gereklilikler

Bu uygulamayı çalıştırmak için ihtiyacınız olanlar:

  • Python 3.7+ Bilgisayarınızda Python kurulu olmalı.
  • requests kütüphanesi Python ile HTTP istekleri yapmak için kullanacağız.
  • OpenWeatherMap API Key Hava durumu verilerini almak için ücretsiz bir API key oluşturacağız. OpenWeatherMap üzerinden birkaç dakika içinde API key alınabilir.
  • https://openweathermap.org/api

💻 Kod:

import requests
from datetime import datetime

class HavaDurumuAgent:
    def __init__(self, sehir):
        self.sehir = sehir
        self.api_key = "BURAYA_API_KEY_GIRECEKSINIZ"  # OpenWeatherMap'ten ücretsiz alabilirsiniz

    def hava_durumunu_kontrol_et(self):
        """Hava durumu verisini API'den çeker"""
        url = f"http://api.openweathermap.org/data/2.5/weather?q={self.sehir}&appid={self.api_key}&units=metric&lang=tr"

        try:
            response = requests.get(url)
            data = response.json()
            return data
        except Exception as e:
            print(f"Hata: {e}")
            return None

    def yagmur_kontrolu(self, hava_data):
        """Yağmur, çisenti veya fırtına olup olmadığını kontrol eder"""
        if hava_data:
            weather = hava_data['weather'][0]['main']
            yagis_durumlari = ["Rain", "Drizzle", "Thunderstorm"]

            if weather in yagis_durumlari:
                return True

        return False

    def hatirlatma_yap(self, hava_data):
        """Kullanıcıya uygun mesaj verir"""
        sicaklik = hava_data['main']['temp']
        durum = hava_data['weather'][0]['description']

        print(f"\n🌤️  {self.sehir} Hava Durumu Raporu")
        print(f"📅 Tarih: {datetime.now().strftime('%d.%m.%Y %H:%M')}")
        print(f"🌡️  Sıcaklık: {sicaklik}°C")
        print(f"☁️  Durum: {durum.capitalize()}")

        if self.yagmur_kontrolu(hava_data):
            print("\n⚠️  UYARI: Yağmur yağacak! Şemsiyeni unutma! ☔")
        else:
            print("\n✅ Hava güzel görünüyor! İyi günler! 😊")

    def calistir(self):
        """Agent'ı çalıştırır - ana iş akışı"""
        print("🤖 Agent çalışmaya başladı...")

        # Adım 1: Veriyi topla
        hava_data = self.hava_durumunu_kontrol_et()

        if hava_data:
            # Adım 2: Analiz et ve karar ver
            # Adım 3: Hatırlatma yap
            self.hatirlatma_yap(hava_data)
        else:
            print("❌ Hava durumu bilgisi alınamadı!")

# Agent'ı kullanma
if __name__ == "__main__":
    agent = HavaDurumuAgent("Istanbul")
    agent.calistir()

Bu örnekte agent ne yapıyor?

Kodun içinde HavaDurumuAgent adında bir sınıf oluşturduk. Bu sınıf küçük bir agent gibi davranıyor.

Önce şehir bilgisini alıyor. Daha sonra OpenWeatherMap API’ye istek göndererek hava durumu verisini çekiyor. Gelen verinin içinde sıcaklık, hava durumu açıklaması ve yağış bilgisi gibi alanları kontrol ediyor. Eğer hava yağmurluysa kullanıcıya şemsiye almasını öneriyor. Yağmur yoksa hava durumunun uygun olduğunu belirten basit bir mesaj veriyor.

Agent’ın akışı şu şekilde çalışıyor:

Şehir bilgisini al
        ↓
OpenWeatherMap API’ye bağlan
        ↓
Hava durumu verisini çek
        ↓
Veriyi analiz et
        ↓
Yağmur var mı kararını ver
        ↓
Kullanıcıya öneri üret

Bu akış, agent mimarisindeki temel fikri oldukça sade bir biçimde gösterir. Bir agent yalnızca cevap üretmez; bir araca bağlanır, veriyi toplar, değerlendirir ve bir sonuca göre aksiyon önerir.

Elbette gerçek dünyadaki agent sistemlerinde bu yapı çok daha gelişmiş olabilir. Örneğin bir sonraki seviyede agent:

  • Kullanıcının doğal dilde sorduğu soruyu anlayabilir
  • Saatlik hava tahminini kontrol edebilir
  • Yağmur ihtimali varsa bildirim, e-posta veya takvim hatırlatması oluşturabilir
  • MCP üzerinden farklı araçlara bağlanabilir

Ama ilk adım için bu örnek bize agent mantığının temelini verir: Veri al, analiz et, karar ver, öneri üret.

🌐 Uygulamanın Çalışan Versiyonu

Bu örneği sadece terminalde çalışan bir Python kodu olarak bırakmak yerine, küçük bir web uygulamasına da dönüştürdüm.

👉 Aşağıdaki bağlantıdan uygulamanın çalışan versiyonunu deneyebilirsiniz:

[embed]🤖 Hava Durumu Agent Yapay zeka destekli akıllı hava durumu asistanınızweatherforecastagent.onrender.com

Bu web versiyonunda kullanıcı şehir adını giriyor, uygulama OpenWeatherMap API üzerinden hava durumunu alıyor ve sıcaklık, nem, rüzgar, hissedilen sıcaklık gibi verileri gösteriyor. Ayrıca “Agent Önerileri” bölümünde hava durumuna göre kısa tavsiyeler üretiyor.

🎓 Örnek 2: Daha Gelişmiş Agent - Görev Yöneticisi

Şimdi bir adım ileri gidelim ve biraz daha gelişmiş bir agent örneği yazalım.

İlk örnekte hava durumu agent’ımız tek bir dış kaynaktan veri çekip basit bir karar veriyordu. Bu örnekte ise durum yönetimi, önceliklendirme ve çoklu karar verme mekanizmalarına sahip bir agent yapacağız.

Senaryomuz şu:

Günlük görevlerinizi yöneten, öncelik sırasına koyan ve size akıllı öneriler sunan bir görev yöneticisi agent’ı geliştireceğiz. Bu agent:

  • Kullanıcıdan görev bilgilerini alacak (başlık, öncelik, son tarih)
  • Görevleri JSON dosyasında saklayacak (veri kalıcılığı)
  • Görevleri öncelik ve tarihe göre sıralayacak
  • Gecikmiş görevleri tespit edecek
  • Bugünkü görevleri vurgulayacak
  • Yaklaşan deadline’ları uyaracak
  • Kullanıcıya hangi görevle başlaması gerektiğini önerecek

Bu örnek, ilk örnekten şu açılardan farklıdır:

  • Durum Hafızası: Görevleri JSON dosyasında saklayarak kalıcılık sağlar
  • Çoklu Karar Mekanizması: Sadece tek bir koşul değil, birden fazla faktörü analiz eder (öncelik, tarih, gecikme durumu)
  • Proaktif Öneriler: Kullanıcı sormadan durum analizi yapıp önerilerde bulunur
  • Dinamik Önceliklendirme: Zaman geçtikçe görevlerin önem sıralaması değişir

📋 Gereklilikler

Bu uygulamayı çalıştırmak için ihtiyacınız olanlar:

  • Python 3.7+ : Bilgisayarınızda Python kurulu olmalı
  • json modülü: Python’da varsayılan olarak gelir, ek kurulum gerektirmez
  • datetime modülü: Python’da varsayılan olarak gelir, tarih/saat işlemleri için
  • Not: Aşağıdaki kod, agent mantığını göstermek için sadeleştirilmiş Python örneğidir. Web uygulaması versiyonunda Flask, HTML, CSS, JavaScript, opsiyonel OpenAI API ve Google Calendar bağlantısı da kullanılmaktadır.

💻 Kod:

from datetime import datetime
import json

class GorevYoneticisiAgent:
    def __init__(self):
        self.gorevler = []
        self.dosya_adi = "gorevler.json"
        self.gorevi_yukle()

    def gorevi_yukle(self):
        """Kaydedilmiş görevleri yükler"""
        try:
            with open(self.dosya_adi, 'r', encoding='utf-8') as f:
                self.gorevler = json.load(f)
        except FileNotFoundError:
            self.gorevler = []

    def gorevi_kaydet(self):
        """Görevleri dosyaya kaydeder"""
        with open(self.dosya_adi, 'w', encoding='utf-8') as f:
            json.dump(self.gorevler, f, ensure_ascii=False, indent=2)

    def gorev_ekle(self, baslik, oncelik="orta", tarih=None):
        """Yeni görev ekler"""
        if tarih is None:
            tarih = datetime.now().strftime('%Y-%m-%d')

        gorev = {
            'id': len(self.gorevler) + 1,
            'baslik': baslik,
            'oncelik': oncelik,  # yüksek, orta, düşük
            'tarih': tarih,
            'tamamlandi': False,
            'olusturma': datetime.now().strftime('%Y-%m-%d %H:%M')
        }

        self.gorevler.append(gorev)
        self.gorevi_kaydet()
        print(f"✅ Görev eklendi: {baslik}")

    def oncelikleri_analiz_et(self):
        """Görevleri önceliğe göre sıralar ve analiz yapar"""
        oncelik_sirasi = {'yüksek': 1, 'orta': 2, 'düşük': 3}

        aktif_gorevler = [g for g in self.gorevler if not g['tamamlandi']]
        sirali_gorevler = sorted(
            aktif_gorevler, 
            key=lambda x: (oncelik_sirasi.get(x['oncelik'], 4), x['tarih'])
        )

        return sirali_gorevler

    def gunluk_rapor(self):
        """Günlük görev raporunu hazırlar"""
        sirali = self.oncelikleri_analiz_et()
        bugun = datetime.now().strftime('%Y-%m-%d')

        print("\n" + "="*50)
        print("📋 GÜNLÜK GÖREV RAPORU")
        print("="*50)
        print(f"📅 Tarih: {datetime.now().strftime('%d.%m.%Y %H:%M')}")
        print(f"📊 Toplam Görev: {len(self.gorevler)}")
        print(f"✅ Tamamlanan: {len([g for g in self.gorevler if g['tamamlandi']])}")
        print(f"⏳ Bekleyen: {len(sirali)}")

        if not sirali:
            print("\n🎉 Harika! Tüm görevleri tamamladın!")
            return

        print("\n🔥 ÖNCELİKLİ GÖREVLER:")
        print("-" * 50)

        for i, gorev in enumerate(sirali[:5], 1):  # İlk 5 görevi göster
            oncelik_emoji = {
                'yüksek': '🔴',
                'orta': '🟡', 
                'düşük': '🟢'
            }

            tarih_obj = datetime.strptime(gorev['tarih'], '%Y-%m-%d')
            gun_farki = (tarih_obj - datetime.now()).days

            tarih_durumu = ""
            if gun_farki < 0:
                tarih_durumu = f"❗ ({abs(gun_farki)} gün gecikti)"
            elif gun_farki == 0:
                tarih_durumu = "⚡ (BUGÜN!)"
            elif gun_farki <= 3:
                tarih_durumu = f"⚠️  ({gun_farki} gün kaldı)"

            print(f"{i}. {oncelik_emoji[gorev['oncelik']]} {gorev['baslik']}")
            print(f"   📅 {gorev['tarih']} {tarih_durumu}")
            print()

    def gorev_tamamla(self, gorev_id):
        """Görevi tamamlanmış olarak işaretle"""
        for gorev in self.gorevler:
            if gorev['id'] == gorev_id:
                gorev['tamamlandi'] = True
                gorev['tamamlanma'] = datetime.now().strftime('%Y-%m-%d %H:%M')
                self.gorevi_kaydet()
                print(f"🎉 Görev tamamlandı: {gorev['baslik']}")
                return
        print("❌ Görev bulunamadı!")

    def akilli_oneri(self):
        """Agent'ın akıllı önerileri"""
        sirali = self.oncelikleri_analiz_et()

        if not sirali:
            return

        print("\n💡 AGENT ÖNERİLERİ:")
        print("-" * 50)

        # Gecikmiş görevleri bul
        geciken = [g for g in sirali 
                   if (datetime.now() - datetime.strptime(g['tarih'], '%Y-%m-%d')).days > 0]

        if geciken:
            print(f"⚠️  {len(geciken)} göreviniz gecikti! Önce onları halletmelisiniz.")

        # Bugünkü görevler
        bugun = datetime.now().strftime('%Y-%m-%d')
        bugunun_gorevleri = [g for g in sirali if g['tarih'] == bugun]

        if bugunun_gorevleri:
            print(f"📌 Bugün {len(bugunun_gorevleri)} göreviniz var.")

        # Yüksek öncelikli görevler
        yuksek = [g for g in sirali if g['oncelik'] == 'yüksek']
        if yuksek:
            print(f"🔴 {len(yuksek)} yüksek öncelikli göreviniz mevcut!")
            print(f"   Öncelikle '{yuksek[0]['baslik']}' ile başlayabilirsiniz.")

    def calistir(self):
        """Agent'ı çalıştır"""
        print("\n🤖 Görev Yöneticisi Agent Aktif!\n")
        self.gunluk_rapor()
        self.akilli_oneri()

# Kullanım örneği
if __name__ == "__main__":
    agent = GorevYoneticisiAgent()

    # Birkaç görev ekleyelim (ilk çalıştırmada)
    agent.gorev_ekle("Proje sunumu hazırla", "yüksek", "2026-05-25")
    agent.gorev_ekle("Email'leri yanıtla", "orta")
    agent.gorev_ekle("Spor yap", "düşük", "2026-05-21")
    agent.gorev_ekle("Rapor gönder", "yüksek", "2026-05-17")

    # Agent'ı çalıştır
    agent.calistir()

    # Bir görevi tamamla
    # agent.gorev_tamamla(1)

Bu örnekte agent ne yapıyor?

Agent’ın çalışma akışı şu şekilde:

1. Veri Yönetimi: Görevleri JSON dosyasında saklar. Uygulama kapansa bile veriler kaybolmaz.

2. Analiz ve Sıralama: Görevleri önceliğe göre sıralar (yüksek → orta → düşük). Aynı öncelikteki görevleri tarihe göre sıralar.

3. Çoklu Karar Mekanizması: Agent birden fazla faktörü aynı anda değerlendirir:

  • Gecikme kontrolü (tarihi geçmiş görevler)
  • Aciliyet kontrolü (bugünkü görevler)
  • Öncelik kontrolü (yüksek öncelikli görevler)
  • Yaklaşan deadline (3 gün içindeki görevler)

4. Proaktif Öneriler: Kullanıcı sormadan durum analizi yapıp öneride bulunur:

⚠️  2 göreviniz gecikti! Önce onları halletmelisiniz.
📌 Bugün 3 göreviniz var.
🔴 4 yüksek öncelikli göreviniz mevcut!
   Öncelikle 'Proje sunumu hazırla' ile başlayabilirsiniz.

Agent’ın karar verme akışı:

Tüm görevleri yükle
        ↓
Aktif görevleri filtrele
        ↓
Öncelik ve tarihe göre sırala
        ↓
Her görev için:
  - Gecikmiş mi? (tarih < bugün)
  - Bugün mü? (tarih = bugün)
  - Acil mi? (tarih ≤ bugün+3)
        ↓
Önerileri kategorize et
        ↓
Kullanıcıya öncelikli listele

🎯 Bu Koddan Ne Öğrendik?

  1. Veri Saklama: JSON kullanarak görevleri kalıcı tutar
  2. Karar Verme: Birden fazla faktörü aynı anda analiz eder
  3. Akıllı Öneriler: Duruma göre kullanıcıya proaktif tavsiyeler verir
  4. Durum Yönetimi: Görevlerin durumunu (aktif/tamamlanmış) takip eder
  5. Önceliklendirme: Görevleri önem sırasına koyar.

🌐 Uygulamanın Çalışan Versiyonu

Bu örneği sadece terminalde çalışan bir Python kodu olarak bırakmak yerine, modern bir web uygulamasına dönüştürdüm.

👉 Aşağıdaki bağlantıdan uygulamanın çalışan versiyonunu deneyebilirsiniz:

[embed]📋 Görev Yöneticisi Agent Yapay zeka destekli akıllı görev takip asistanınıztaskmanageragent.onrender.com

Bu web versiyonunda:

  • Görev Ekleme Formu: Başlık, öncelik ve son tarih ile yeni görev oluşturma
  • 📊 Günlük Rapor İstatistikleri: Toplam, tamamlanan ve bekleyen görev sayıları
  • 🤖 Akıllı Agent Önerileri: Gecikmiş görevler, bugünkü görevler, yüksek öncelikli görevler
  • 🧠 Doğal Kural Tabanlı Öneri: OpenAI kapalı olsa bile daha açıklayıcı öneri üretme
  • 🗓️ Google Calendar Bağlantısı: Görevi Google Calendar’a eklenebilir hale getirme
  • 🌍 Türkçe / İngilizce Arayüz: Uygulamayı iki dilde kullanabilme
  • ✓ Görev Tamamlama ve Silme: Tek tıkla görev yönetimi
  • 📱 Responsive Tasarım: Mobil ve masaüstü uyumlu

Bu versiyon da hâlâ orta seviye bir agent örneğidir. Ancak terminalde çalışan örneğe göre çok daha etkileşimli ve kullanıcı dostu bir deneyim sunar.

Özellikle agent’ın “durum analizi → önceliklendirme → akıllı öneriler” akışını görsel arayüzde daha net görmemizi sağlar.

🎯 İki Örnek Arasındaki Farklar

Hava Durumu Agent’ı ve Görev Yöneticisi Agent’ı

Created by the author — Comparison of the simple weather agent and the more advanced task manager agent

Created by the author — Comparison of the simple weather agent and the more advanced task manager agent

Tabloya bakınca fark net görünüyor: Örnek 1 dış bir API’ye bağlanıyor ve tek bir koşula göre karar veriyor. Örnek 2 ise kendi verisini tutuyor, birden fazla faktörü aynı anda değerlendiriyor ve siz sormadan öneride bulunuyor.

Bu iki örnek şunu gösteriyor: bir agent sadece “veri çekip cevap verme” işlemi yapmaz. Veriyi organize eder, birden fazla faktörü analiz eder, zaman içinde değişen durumları takip eder ve kullanıcıya en önemli bilgiyi öne çıkarır.

🔌 Bölüm 3: MCP İle Tanışalım

🎓 MCP’nin Teknik Yapısı

MCP, yapay zeka modellerinin dış kaynaklara (dosyalar, veri tabanları, API’ler) erişmesi için Anthropic tarafından geliştirilen açık kaynak bir protokoldür.

Bölüm 1'de MCP’yi priz analojisiyle açıkladık. Şimdi bir adım ileri gidip bu protokolün teknik katmanlarına bakalım.

MCP mimarisi üç ana bileşenden oluşur:

  • AI Model (İstemci): Claude, GPT gibi büyük dil modelleri. İsteği başlatan taraf.
  • MCP Server (Aracı): Modelin isteklerini alıp ilgili veri kaynağına ileten katman.
  • Veri Kaynakları: Dosya sistemi, API’ler, veri tabanları ve diğer harici sistemler.

Created by the author — The three main components of MCP architecture: model, MCP server, and external data sources

Created by the author — The three main components of MCP architecture: model, MCP server, and external data sources

Model, MCP protokolü aracılığıyla sunucuyla konuşur. Sunucu ise hangi veriye nasıl erişileceğini bilir ve güvenli biçimde köprü görevi görür.

MCP’nin Asıl Çözdüğü Problem

Yapay zeka dünyasına bir süre girmişseniz şu isimlerle mutlaka karşılaşmışsınızdır: LangChain, LlamaIndex, CrewAI, OpenAI Agents, Google ADK, HuggingFace smolagents… Liste uzuyor…

Hepsinin ortak hedefi aynı: LLM’leri dış dünyaya bağlamak.

Ve hepsinin ortak bir derdi var.

Diyelim ki yapay zekanıza DuckDuckGo ile web araması yaptırma yeteneği kazandırmak istiyorsunuz. LangChain bunu kendi DuckDuckGoSearchTool sınıfıyla yapıyor. CrewAI aynı iş için farklı bir yapı kullanıyor. LlamaIndex başka bir format bekliyor. Yani aynı iş, her framework için sıfırdan tekrar yazılıyor.

Ya da yapay zekanıza bir takvim entegrasyonu yazmak istiyorsunuz. LangChain bunun için kendi sınıfını bekliyor. CrewAI kendi tool formatını. LlamaIndex başka bir yapı. Yani Google Calendar’a bağlanmak için aynı mantığı üç kez, üç farklı dilde yazıyorsunuz. Sabah LangChain projesi için yazdınız, öğleden sonra CrewAI projesinde aynı şeye ihtiyaç duydunuz, sıfırdan tekrar.

Ekosistem büyüdükçe bu tekrar katlanıyor. Onlarca framework, her biri kendi diliyle, aynı araçları defalarca yeniden icat ediyor.

MCP bu noktada farklı bir soru soruyor:

“Ya bu entegrasyonu bir kere yazsaydınız ve istediğiniz her sisteme takabilseydiniz?”

Kısaca: bu araçları her framework için ayrı ayrı yazmak yerine, bir kere yaz. Standart bir sunucu olarak tanımla. Hangi framework, hangi dil, hangi model kullanırsa kullansın, hepsi aynı MCP sunucusuna bağlansın.

Takvim entegrasyonunu bir MCP sunucusu olarak yazıyorsunuz. Artık LangChain de oraya bağlanıyor, kendi agent’ınız da, ileride kullanacağınız yeni bir framework de. Entegrasyon değişmedi, sadece fişi başka yere taktınız.

İşte bölüm 1' deki priz standardı tam olarak buydu. Cihaz değişiyor, priz aynı kalıyor.

MCP’nin Gerçek Dünyası

Şu an aktif olarak kullanılan MCP sunucularından birkaçına bakalım:

GitHub MCP: Repo oluşturma, commit atma, PR açma, branch yönetimi. Claude’a “şu dosyayı düzenle, commit at” diyebiliyorsunuz.

Slack MCP: Kanal yönetimi, mesaj gönderme, geçmiş okuma. Kod yazmakla hiç alakası yok; model bir iletişim aracını yönetiyor.

PostgreSQL MCP: Veri tabanına read-only erişim. Model şema bilgisini çekip ona göre SQL yazıyor, siz şemayı tekrar tekrar prompt’a yapıştırmak zorunda kalmıyorsunuz.

Puppeteer MCP: Tarayıcı otomasyonu ve web scraping. Model tarayıcınızda gezebiliyor.

AWS MCP: Amazon, kendi servislerine erişim sağlayan resmi bir MCP sunucusu yayımladı. Dokümantasyon çekme, maliyet analizi, şablon kodlar.

Google MCP Toolbox for Databases: Google’ın açık kaynak olarak yayımladığı production-grade MCP sunucusu. PostgreSQL, MySQL, BigQuery, Spanner, AlloyDB dahil onlarca veri tabanını destekliyor. Siz sadece bir tools.yaml dosyasına bağlantı bilgilerini ve araçları tanımlıyorsunuz, binary'yi çalıştırıyorsunuz ve MCP endpoint otomatik hazır hale geliyor. Bağlantı havuzu yönetimi, OAuth2 kimlik doğrulama, OpenTelemetry izleme gibi production karmaşıklıklarını sizin yerinize hallediyor.

Bizim bu bölümde elle yaptığımız şeylerin kurumsal ölçekteki versiyonu. Buradan inceleyebilirsiniz → github.com/googleapis/mcp-toolbox

Hepsinin ortak noktasına dikkat edin: bunların hiçbirinde “bu model için özel yazılmış entegrasyon” yok. Hepsi aynı protokolü konuşuyor. Cursor kullanıyorsanız da GitHub MCP’yi bağlayabilirsiniz, Claude Desktop kullanıyorsanız da, kendi yazdığınız agent’la da. Sunucu bir kez yazıldı, her yere takılıyor.

Bugün Claude kullanıyorsunuz, yarın başka bir modele geçiyorsunuz ama bağladığınız MCP sunucuları olduğu gibi duruyor, yeniden yazmanıza gerek yok.

🎓 Örnek 3: MCP yazalım - Döviz Kuru MCP Sunucusu

Şimdiye kadar örneklerimizde agent’ın kendisini inceledik. Bu örnekte odak değişiyor:

“Bir yapay zekaya güncel döviz kuru sorgulama yeteneği kazandırmak için bir MCP sunucusu nasıl yazılır?”

Senaryomuz şu:

Bir AI agent çalışıyor ve kullanıcı ona şunu soruyor: “100 dolar kaç TL eder?” Agent bu soruyu anlıyor ama güncel döviz kurunu bilmiyor, çünkü eğitim verisi gerçek zamanlı değil. İşte burada MCP devreye giriyor.

Agent, döviz kuru MCP sunucusunu çağırıyor. Sunucu önce Frankfurter API’ye bağlanıyor; eğer istenen para birimi orada desteklenmiyorsa (QAR, AED, SAR gibi Körfez para birimleri) otomatik olarak fawazahmed0 API’ye düşüyor. Güncel kuru alıyor ve agent’a standart formatta geri döndürüyor. Agent artık soruyu doğru yanıtlayabiliyor.

Bu uygulamada 4 araç sunuyoruz:

  • kur_sorgula:İki para birimi arasındaki anlık kuru döner
  • kur_cevir:Belirtilen miktarı bir para biriminden diğerine çevirir
  • kur_listele:Tüm desteklenen para birimlerini listeler
  • kur_gecmis:Son 7 günün kur geçmişini ve mini grafiğini gösterir

⚠️ Başlamadan Önce: Bu Kod “Gerçek MCP” mi?

Kısa cevap: Hayır. Bu kod, MCP’nin mantığını simüle eden bir Python uygulamasıdır; gerçek MCP protokolünün birebir kendisi değildir.

Bunu baştan söylüyorum çünkü bu ayrım önemli. DovizMCPSunucu sınıfı ve Flask üzerinden sunduğumuz HTTP API; araç yönetimi, standart istek-yanıt yapısı, fallback mekanizması ve veri kaynağını agent’tan soyutlama gibi MCP’nin düşünce biçimini doğru temsil eder. Ancak teknik olarak bu yapı bir HTTP API’dir. LangChain veya başka bir sistem buna bağlanmak isterse /api/mcp endpoint’ini özel olarak tanıması gerekir. Yani evrensel bir MCP sunucusu değil, bizim uygulamamıza özel bir arayüzdür.

Gerçek MCP implementasyonları ise genellikle stdio veya streamable HTTP/SSE gibi transport katmanları üzerinden çalışır. Bu sayede Claude Desktop, Cursor veya VS Code gibi MCP uyumlu client’lar, gerçek bir MCP sunucusuna özel entegrasyon kodu yazmadan doğrudan bağlanabilir.

Bu yazıda simülasyon yaklaşımını kullanıyoruz çünkü amacımız en başta protokol detaylarına gömülmek değil, MCP’nin düşünce yapısını anlamak. Yazının sonunda ise aynı sınıfı koruyarak bu yapıyı gerçek bir MCP sunucusuna nasıl dönüştürebileceğimizi de göstereceğiz.

📋 Gereklilikler:

  • Python 3.7+
  • flask, requests , pip install flask requests
  • İnternet bağlantısı (Frankfurter API’ye erişim için)
  • API key gerekmez

💻 Kod:


import requests
import time
from datetime import datetime, timedelta

FRANKFURTER = "https://api.frankfurter.app"
FAWAZ_URL   = "https://latest.currency-api.pages.dev/v1"
FAWAZ_CDN   = "https://cdn.jsdelivr.net/npm/@fawazahmed0/currency-api@latest/v1"

def _get(url, params=None, retries=3):
    """Retry mekanizmalı HTTP GET — geçici hatalarda 3 kez dener."""
    last = None
    for i in range(retries):
        try:
            r = requests.get(url, params=params, timeout=8)
            if r.status_code == 200:
                return r
            last = r
        except (requests.exceptions.Timeout, requests.exceptions.ConnectionError):
            last = None
        if i < retries - 1:
            time.sleep(0.4 * (i + 1))
    return last

def _fawaz_rate(kaynak: str, hedef: str) -> dict | None:
    """fawazahmed0/exchange-api üzerinden kur çeker (200+ para birimi).
    jsDelivr primary, Cloudflare fallback."""
    for base_url in [FAWAZ_CDN, FAWAZ_URL]:
        res = _get(f"{base_url}/currencies/{kaynak.lower()}.json")
        if res and res.status_code == 200:
            data = res.json()
            kur = data.get(kaynak.lower(), {}).get(hedef.lower())
            if kur is not None:
                return {"kur": round(kur, 6), "tarih": data.get("date", ""), "kaynak_api": "fawazahmed0"}
    return None

def _fawaz_rate_on_date(kaynak: str, hedef: str, tarih: str) -> float | None:
    """Belirli bir tarih için fawazahmed0'dan kur çeker."""
    for base_url in [
        f"https://cdn.jsdelivr.net/npm/@fawazahmed0/currency-api@{tarih}/v1",
        f"https://{tarih}.currency-api.pages.dev/v1",
    ]:
        res = _get(f"{base_url}/currencies/{kaynak.lower()}.json")
        if res and res.status_code == 200:
            data = res.json()
            kur = data.get(kaynak.lower(), {}).get(hedef.lower())
            if kur is not None:
                return round(kur, 6)
    return None

class DovizMCPSunucu:
    """
    Döviz kuru sorgulama MCP sunucusu — simülasyon versiyonu.
    MCP'nin mantığını göstermek için HTTP/Flask üzerinden çalışır.
    Gerçek MCP protokolüne dönüşüm için yazının ilerleyen bölümüne bakın.
    """

    def __init__(self):
        self.yetenekler = {
            "kur_sorgula": "İki para birimi arasındaki güncel kuru döner",
            "kur_cevir":   "Belirtilen miktarı bir para biriminden diğerine çevirir",
            "kur_listele": "Desteklenen tüm para birimlerini listeler",
            "kur_gecmis":  "Son 7 günün kur geçmişini döner",
        }

    def kur_sorgula(self, kaynak: str, hedef: str):
        kaynak = kaynak.upper().strip()
        hedef  = hedef.upper().strip()
        if kaynak == hedef:
            return {"hata": "Kaynak ve hedef para birimi aynı olamaz."}

        # 1) Frankfurter — ECB verisi, ~33 para birimi
        try:
            res = _get(f"{FRANKFURTER}/latest", params={"from": kaynak, "to": hedef})
            if res and res.status_code == 200:
                data = res.json()
                kur  = data["rates"].get(hedef)
                if kur is not None:
                    return {
                        "basarili": True, "kaynak": kaynak, "hedef": hedef,
                        "kur": kur, "tarih": data.get("date"),
                        "aciklama": f"1 {kaynak} = {kur} {hedef}",
                        "kaynak_api": "frankfurter",
                    }
        except Exception:
            pass

        # 2) fawazahmed0 fallback — QAR, AED, SAR ve 200+ para birimi
        try:
            fb = _fawaz_rate(kaynak, hedef)
            if fb:
                return {
                    "basarili": True, "kaynak": kaynak, "hedef": hedef,
                    "kur": fb["kur"], "tarih": fb["tarih"],
                    "aciklama": f"1 {kaynak} = {fb['kur']} {hedef}",
                    "kaynak_api": "fawazahmed0",
                }
        except Exception:
            pass

        return {"hata": f"'{kaynak}' veya '{hedef}' para birimi desteklenmiyor."}

    def kur_cevir(self, miktar: float, kaynak: str, hedef: str):
        kaynak = kaynak.upper().strip()
        hedef  = hedef.upper().strip()
        try:
            miktar = float(miktar)
            if miktar <= 0:
                return {"hata": "Miktar sıfırdan büyük olmalıdır."}
        except (ValueError, TypeError):
            return {"hata": "Geçersiz miktar. Sayısal bir değer girin."}

        sonuc = self.kur_sorgula(kaynak, hedef)
        if "hata" in sonuc:
            return sonuc
        cevrilen = round(miktar * sonuc["kur"], 4)
        return {
            "basarili": True, "kaynak": kaynak, "hedef": hedef,
            "miktar": miktar, "kur": sonuc["kur"], "sonuc": cevrilen,
            "tarih": sonuc["tarih"],
            "aciklama": f"{miktar} {kaynak} = {cevrilen} {hedef}",
            "kaynak_api": sonuc.get("kaynak_api"),
        }

    def kur_listele(self):
        # fawazahmed0 primary — 200+ para birimi
        try:
            for base_url in [FAWAZ_CDN, FAWAZ_URL]:
                res = _get(f"{base_url}/currencies.json")
                if res and res.status_code == 200:
                    data = res.json()
                    liste = [
                        {"kod": k.upper(), "isim": v if isinstance(v, str) else k.upper()}
                        for k, v in sorted(data.items())
                    ]
                    return {"basarili": True, "toplam": len(liste), "para_birimleri": liste}
        except Exception:
            pass

        # Frankfurter fallback
        try:
            res = _get(f"{FRANKFURTER}/currencies")
            if res and res.status_code == 200:
                data = res.json()
                liste = [{"kod": k, "isim": v} for k, v in sorted(data.items())]
                return {"basarili": True, "toplam": len(liste), "para_birimleri": liste}
        except Exception:
            pass

        return {"hata": "Para birimi listesi alınamadı."}

    def kur_gecmis(self, kaynak: str, hedef: str):
        kaynak = kaynak.upper().strip()
        hedef  = hedef.upper().strip()
        bitis     = datetime.today()
        baslangic = bitis - timedelta(days=6)

        # 1) Frankfurter
        try:
            res = _get(
                f"{FRANKFURTER}/{baslangic.strftime('%Y-%m-%d')}..{bitis.strftime('%Y-%m-%d')}",
                params={"from": kaynak, "to": hedef},
            )
            if res and res.status_code == 200:
                data  = res.json()
                gecmis = [
                    {"tarih": t, "kur": kurlar.get(hedef)}
                    for t, kurlar in sorted(data.get("rates", {}).items())
                    if kurlar.get(hedef) is not None
                ]
                if gecmis:
                    return {
                        "basarili": True, "kaynak": kaynak, "hedef": hedef,
                        "gecmis": gecmis, "gun_sayisi": len(gecmis),
                        "kaynak_api": "frankfurter",
                    }
        except Exception:
            pass

        # 2) fawazahmed0 fallback — gün gün sorgula
        try:
            gecmis = []
            for i in range(7):
                gun = (baslangic + timedelta(days=i)).strftime("%Y-%m-%d")
                kur = _fawaz_rate_on_date(kaynak, hedef, gun)
                if kur is not None:
                    gecmis.append({"tarih": gun, "kur": kur})
            if gecmis:
                return {
                    "basarili": True, "kaynak": kaynak, "hedef": hedef,
                    "gecmis": gecmis, "gun_sayisi": len(gecmis),
                    "kaynak_api": "fawazahmed0",
                }
        except Exception:
            pass

        return {"hata": f"'{kaynak}' veya '{hedef}' para birimi desteklenmiyor."}

    def istek_isle(self, istek: dict):
        method = istek.get("method")
        params = istek.get("params", {})

        EN_ALIASES = {
            "get_rate": "kur_sorgula", "convert": "kur_cevir",
            "list_currencies": "kur_listele", "rate_history": "kur_gecmis",
        }
        method = EN_ALIASES.get(method, method)

        kaynak = params.get("kaynak") or params.get("from") or ""
        hedef  = params.get("hedef")  or params.get("to")   or ""
        miktar = params.get("miktar") or params.get("amount") or 1

        if method == "kur_sorgula":   return self.kur_sorgula(kaynak, hedef)
        elif method == "kur_cevir":   return self.kur_cevir(miktar, kaynak, hedef)
        elif method == "kur_listele": return self.kur_listele()
        elif method == "kur_gecmis":  return self.kur_gecmis(kaynak, hedef)
        elif method == "yetenekler":  return {"yetenekler": self.yetenekler}
        else: return {"hata": f"Bilinmeyen method: {method}"}

Bu örnekte MCP sunucu ne yapıyor?

DovizMCPSunucu sınıfı, bir AI agent'ın ihtiyaç duyduğu döviz kuru yeteneğini MCP mantığıyla sunuyor.

Bu versiyonda iki önemli ek var: retry mekanizması ve fallback sistemi.

Sunucunun çalışma akışı:

Agent'tan istek gelir (method + params)
        ↓
istek_isle() metodu isteği karşılar
        ↓
İlgili metot çalışır (kur_sorgula / kur_cevir / ...)
        ↓
Önce Frankfurter API denenir (~33 para birimi, ECB verisi)
        ↓
Desteklenmiyorsa fawazahmed0'a düşer (200+ para birimi)
        ↓
Gelen veri standart formatta döner — kaynak_api alanı kimin cevapladığını gösterir

Burada kritik bir nokta var: veri kaynağının değişmesi agent’ı etkilemiyor. Frankfurter mı cevap verdi, fawazahmed0 mi? Agent her zaman aynı formatta yanıt alıyor. MCP’nin “standart arayüz” vaadi tam olarak bu.

Bu örnekte agent şunu yapabilir: “100 USD kaç TL?” sorusunu aldığında kur_cevir metodunu çağırır, {miktar: 100, kaynak: "USD", hedef: "TRY"} parametrelerini gönderir ve sonucu alır. Gerçek zamanlı, doğru veri ve herhangi bir ek eğitim olmadan.

🌐 Uygulamanın Çalışan Versiyonu

Yazdığımız kodu terminalde çalıştırmakla bırakmadık. Bu MCP sunucusunu bir web uygulamasına dönüştürdük — hem görünür hem etkileşimli bir playground olsun diye.

Arayüzde sol taraftan bir araç seçip formu dolduruyor, “MCP’ye Gönder” butonuna basıyorsunuz.

Sol paneldeki 5 adım sırayla yanıyor: siz → agent → protokol → MCP sunucu → API → geri dönüş. Her adım aktifken hangi katmanda olduğunuzu görüyorsunuz.

Sağ panelde ham JSON görünüyor, hem gönderilen isteği (method + params) hem dönen yanıtı. Yanıttaki kaynak_api alanı hangi API'nin kullandığını da açıkça gösteriyor: Frankfurter mı, fawazahmed0 mi?

kur_gecmis aracında son 7 günün verisi bar grafik olarak görselleştiriliyor. Türkçe/İngilizce arayüz ve karanlık/aydınlık mod desteği de mevcut.

Kodun kendisi veri mantığını gösteriyorsa, uygulama o mantığın nasıl bir akışa dönüştüğünü gösteriyor. İkisi birbirini tamamlıyor.

👉 Aşağıdaki bağlantıdan uygulamanın çalışan versiyonunu deneyebilirsiniz:

[embed]Döviz MCP Sunucusu currencymcpserver.onrender.com

🎯 Bu Koddan Ne Öğrendik?

  • MCP bir yetenek katmanı: Agent’ın bilmediği bir şeyi (güncel döviz kuru) MCP sunucusu üzerinden öğreniyor.
  • Fallback sistemi: Veri kaynağı değişse bile agent etkilenmiyor, standart yanıt formatı korunuyor.
  • Tek sorumluluk: Sunucu sadece döviz kurlarını biliyor. Agent karar veriyor, sunucu veriyi sağlıyor.
  • Dış API’ler MCP’nin veri kaynağı olabilir: Dosya sistemiyle sınırlı değil; internet üzerindeki herhangi bir servis MCP’ye bağlanabilir.
  • Standart arayüz değişmiyor: method + params formatı, veri kaynağı ne olursa olsun aynı.
  • Bir kez yaz, her yerde kullan: Bu sunucuyu LangChain’e de, kendi agent’ınıza da, gerçek MCP protokolüne de bağlayabilirsiniz, sunucu değişmez.

🔌 Peki Bu Gerçek MCP’ye Nasıl Dönüşür?

Aynı DovizMCPSunucu sınıfını değiştirmeden, etrafına küçük bir MCP wrapper katmanı ekleyerek bu yapıyı gerçek MCP protokolüne dönüştürebiliriz:


pip install mcp

# gercek_mcp_server.py

from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp.types import Tool, TextContent

import asyncio
import json

from mcp_server import DovizMCPSunucu

server = Server("doviz-mcp")
doviz = DovizMCPSunucu()

@server.list_tools()
async def list_tools():
    return [
        Tool(
            name="kur_sorgula",
            description="İki para birimi arasındaki güncel kuru döner",
            inputSchema={
                "type": "object",
                "properties": {
                    "kaynak": {"type": "string"},
                    "hedef": {"type": "string"},
                },
                "required": ["kaynak", "hedef"],
            },
        ),
        Tool(
            name="kur_cevir",
            description="Belirtilen miktarı bir para biriminden diğerine çevirir",
            inputSchema={
                "type": "object",
                "properties": {
                    "miktar": {"type": "number"},
                    "kaynak": {"type": "string"},
                    "hedef": {"type": "string"},
                },
                "required": ["miktar", "kaynak", "hedef"],
            },
        ),
        Tool(
            name="kur_listele",
            description="Desteklenen tüm para birimlerini listeler",
            inputSchema={
                "type": "object",
                "properties": {},
            },
        ),
        Tool(
            name="kur_gecmis",
            description="Son 7 günün kur geçmişini döner",
            inputSchema={
                "type": "object",
                "properties": {
                    "kaynak": {"type": "string"},
                    "hedef": {"type": "string"},
                },
                "required": ["kaynak", "hedef"],
            },
        ),
    ]

@server.call_tool()
async def call_tool(name: str, arguments: dict):
    sonuc = doviz.istek_isle({
        "method": name,
        "params": arguments,
    })

    return [
        TextContent(
            type="text",
            text=json.dumps(sonuc, ensure_ascii=False, indent=2),
        )
    ]

async def main():
    async with stdio_server() as streams:
        await server.run(
            streams[0],
            streams[1],
            server.create_initialization_options(),
        )

if __name__ == "__main__":
    asyncio.run(main())

Bu dosyayı çalıştırdıktan sonra Claude Desktop config dosyasına şunu ekliyorsunuz:

{
  "mcpServers": {
    "doviz-mcp": {
      "command": "python",
      "args": ["/tam/yol/gercek_mcp_server.py"]
    }
  }
}

Claude Desktop’ı yeniden başlatıyorsunuz. Artık Claude’a “100 dolar kaç TL eder?” veya “bu hafta dolar ne kadar değişti?” dediğinizde Claude otomatik olarak senin sunucunu çağırıyor. Hiçbir ek entegrasyon kodu yazmadan.

MCP Yazmak İçin Anthropic’in Paketini Kullanmak Zorunda mısın?

Hayır. MCP açık bir standarttır. Anthropic protokolü tanımladı ve açık kaynak olarak yayımladı, ama kimse Anthropic’in paketini kullanmak zorunda değil. TypeScript, Go, Rust implementasyonları da mevcut. Kurallar belirli, dil serbest.

💡 Peki Ne Zaman MCP Yazmalısınız?

MCP sunucusu yazmak her durumda anlamlı olmayabilir. İki senaryo var:

Global kullanım için: Hazırda benzeri olmayan bir entegrasyon geliştiriyorsanız ve bunu MCP ekosistemine katkı olarak sunmak istiyorsanız MCP sunucusu yazmak değerli. Örneğin henüz MCP sunucusu bulunmayan bir servis veya kuruma özel bir sistem.

Lokal/kişisel kullanım için: Kendi geliştirdiğiniz bir aracı veya iç sisteminizi bir LLM’e bağlamak istiyorsanız MCP yazmak en temiz yol. Şirket içi bir veri tabanı, kendi yazdığınız bir API, sadece sizin kullandığınız bir araç, bunların hepsini MCP üzerinden Claude Desktop veya Cursor’a bağlayabilirsiniz.

Ama şunu not düşmek gerek: Döviz kuru gibi yaygın ihtiyaçlar için dünyanın dört bir yanından zaten yazılmış MCP sunucuları mevcut. Bizim bu örnekteki amacımız MCP’yi nasıl yazacağınızı en basit yoldan somut olarak göstermekti, yoksa döviz kuru için sıfırdan bir MCP sunucusu yazıp Claude’a tanıtmak pratikte pek gerekmez. Gerçek değer, başkasının çözmediği problemi çözdüğünüzde ortaya çıkıyor.

📖 Son Olarak: Simülasyon ve Gerçek MCP Arasındaki Fark

Bu yazıda yazdığımız (simülasyon): Flask + HTTP endpoint. MCP’nin mantığını gösteriyor. Kendi sisteminize özgü. Flask bilen herkes anlayabilir, tarayıcıdan test edilebilir, deploy etmesi kolay.

Gerçek MCP protokolü: stdio / SSE üzerinden haberleşir. Claude Desktop, Cursor, VS Code gibi MCP uyumlu her client direkt bağlanabilir. Evrensel standarttır.

Hangisini ne zaman kullanmalısınız?

Tek soru şu: “Bu sunucuyu sadece kendi sistemimde mi kullanacağım, yoksa herhangi bir MCP client’a mı bağlamak istiyorum?” Kendi sisteminiz için simülasyon yeterli; Claude Desktop veya başka bir MCP client için gerçek protokol gerekli.

Yazının başında “MCP nedir diye aratmanıza gerek kalmayacak, çünkü siz zaten kendi MCP’nizi yazmış olacaksınız” demiştik. Umarım bu noktaya birlikte gelmişizdir. 💪

Bu yazıda MCP’yi yalnızca teorik bir kavram olarak değil, agent mimarisi içinde nerede konumlandığını göstererek ele aldık. Önce basit agent örnekleriyle “karar veren sistem” fikrini kurduk. Ardından MCP’nin bu sistemlere dış dünyayla konuşma yeteneği kazandıran standart bir katman olduğunu gördük. Son olarak da Flask tabanlı simülasyon ile gerçek MCP protokolü arasındaki farkı netleştirdik.

Bu yazının devamında isterseniz gercek_mcp_server.py dosyasını Claude Desktop'a bağlayıp canlı çalışan bir örnek üzerinden adım adım ilerleyebiliriz. Eğer böyle bir devam yazısı görmek isterseniz yorumlarda belirtin; bir sonraki bölümde gerçek MCP sunucusunu Claude Desktop ile birlikte çalıştırıp uçtan uca test edelim. 🔌

Yazıda bahsettiğim örnek projelerin kodlarını incelemek isterseniz GitHub repolarına buradan ulaşabilirsiniz:

*🤖 Hava Durumu Agent*

*📋 Görev Yöneticisi Agent*

*💱 Döviz MCP Sunucusu*

Bu yazı faydalı olduysa 👏 alkışlamayı, 💾 kaydetmeyi ve 🔄 paylaşmayı unutmayın. Sorularınız için yorumlar bölümü açık!

Projelerim ve içeriklerim hakkında güncellemelerden haberdar olmak için benimle 👉 LinkedIn’de bağlantıda kalabilirsiniz.


메타데이터
post_id
b3be16d26f8a
slug
mcp-nedir-model-context-protocol-agent-rehberi-b3be16d26f8a
url
https://medium.com/@hincalgunal/mcp-nedir-model-context-protocol-agent-rehberi-b3be16d26f8a
canonical_url
https://medium.com/@hincalgunal/mcp-nedir-model-context-protocol-agent-rehberi-b3be16d26f8a
author_url
https://medium.com/@hincalgunal
status
ok
fetched_at
2026-06-09 15:37:30