Özel Fonksiyonlardan Standart MCP Mimarisine Geçiş

Bir uygulamaya geniş dil modeli (LLM) tabanlı araç çağırma (tool-calling) eklemek istediğinizde, kendinizi kaçınılmaz olarak her model sağlayıcısına göre ayrı ayrı formatlanmış devasa JSON şemaları ve kırılgan HTTP uç noktaları arasında debelenirken bulursunuz. OpenAI'ın Function Calling biçimi, Anthropic'in Tool Use yapısı ve Gemini'nin Function Declarations sözdizimi arasındaki küçük semantik farklar, kod tabanını hızla yönetilemez hale getirir. Hacker News üzerinde paylaşılan ve Garmin Connect verilerini yerel bir MCP sunucusu üzerinden LLM bağlamına aktaran çalışmayı incelediğimde, bu protokolün yalnızca Claude Desktop veya IDE eklentileriyle sınırlı bir heves olmadığını; modern web ve mobil uygulamalarda bağlam yönetimini kökten değiştirebilecek açık bir standart sunduğunu çok daha net gördüm.
Kırılgan Fonksiyon Sarmalayıcıların Sınırları
Geleneksel mimarilerde bir mobil veya web uygulamasının LLM ile harici servisler arasında köprü kurması, arka planda doğrudan API çağrıları yapan ve modelin ürettiği parametreleri elle doğrulayan özel sarmalayıcılara (wrapper) dayanır. Bu yaklaşımda model istemci tarafına gömülü bir JSON şemasıyla yönlendirilir; modelden gelen yanıt uygulama katmanında parse edilir, doğrulama adımlarından geçirilir, ilgili REST uç noktasına gönderilir ve dönen ham JSON çıktısı tekrar sisteme bir sistem mesajı olarak enjekte edilir. Bu döngü ilk üç araç için sorunsuz çalışıyor gibi görünse de araç sayısı 15-20 bandına çıktığında bağlam penceresi (context window) kirlenir, modelin parametre halüsinasyonu yapma olasılığı artar ve şema güncellemeleri tüm istemcilerin yeniden derlenmesini zorunlu kılar.
Üstelik bu yaklaşım, uygulamanın veri katmanı ile yapay zeka sağlayıcısını birbirine sıkı sıkıya bağlar. Bir sağlayıcıdan diğerine geçmek ya da yerel bir açık kaynak modeli (örneğin Ollama üzerinden Llama 3) devreye almak istediğinizde, tüm araç tanımlarını ve doğrulama mantığını baştan yazmak gerekir. İşte bu noktada Model Context Protocol (MCP), istemci ile veri kaynakları arasına standart bir soyutlama katmanı yerleştirerek karmaşıklığı ayrıştırır.
Model Context Protocol Mimarisi Nasıl Çalışır?
Anthropic tarafından açık standart olarak duyurulan MCP, özünde istemci (client) ve sunucu (server) mimarisine dayanan, JSON-RPC 2.0 protokolü üzerinden haberleşen iki yönlü bir protokoldür. Protokol üç temel ilke üzerine inşa edilmiştir: Kaynaklar (Resources), İstemler (Prompts) ve Araçlar (Tools). Araçlar istemciye yürütülebilir fonksiyonlar sunarken, Kaynaklar dosya veya API verisi gibi salt okunur bağlamları modele aktarır. Hacker News'teki Garmin örneğinde olduğu gibi, bir saatten gelen nabız veya uyku metrikleri birer 'Resource' olarak tanımlanırken, yeni bir antrenman rotası oluşturma eylemi bir 'Tool' olarak sunulur.
Model Context Protocol, web geliştiricilerinin HTTP ve REST ile yakaladığı birlikte çalışabilirlik seviyesini, yapay zeka ajanları ile veri kaynakları arasına taşımayı amaçlayan bir JSON-RPC standardıdır.
MCP iki ana taşıma katmanı (transport layer) destekler: yerel süreçler arası iletişim için standart girdi/çıktı (stdio) ve uzak ağ servisleri için Server-Sent Events (SSE) tabanlı HTTP. Mobil ve web uygulamalarında stdio doğrudan kullanılamadığından, mimari tasarımda SSE taşıma katmanı öne çıkar. Sunucu, istemciye mevcut araçların şemasını dinamik olarak bildirir; model bir aracı çağırmaya karar verdiğinde bu istek MCP sunucusuna iletilir, sonuç ise standart bir formatta istemciye döner.
Sunucu Tarafında MCP Tasarımı ve Uygulama Pratiği
Sürdürülebilir bir MCP sunucusu tasarlarken TypeScript ekosistemindeki resmi @modelcontextprotocol/sdk kütüphanesi (v1.x) güvenli ve öngörülebilir bir temel sağlar. Sunucu tarafında araç tanımlarını yaparken Zod gibi şema doğrulayıcılarla tip güvenliğini garanti altına almak, modelin geçersiz parametre göndermesi durumunda API uç noktalarımızın çökmesini engeller. Aşağıdaki örnekte, kullanıcının belirli bir tarih aralığındaki aktivite verilerini getiren yalın bir MCP aracı görülmektedir:
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
const server = new McpServer({ name: "health-api", version: "1.0.0" });
server.tool("getActivities", { days: z.number().min(1).max(30) }, async ({ days }) => {
const data = await fetchActivitiesFromDB(days);
return { content: [{ type: "text", text: JSON.stringify(data) }] };
});
Bu yapının getirdiği en büyük avantaj, aracın girdi şemasının protokol tarafından otomatik olarak JSON Schema biçimine dönüştürülmesidir. Uygulama tarafındaki LLM orkestrasyon motoru bu şemayı sunucudan tek bir sorguyla (tools/list) dinamik olarak çeker. Böylece uygulamanın kaynak kodunda tek bir satır dahi tool-calling JSON'ı yazmak zorunda kalmazsınız. Veritabanı şemanız veya API parametreleriniz değiştiğinde, yalnızca MCP sunucusunu güncellemeniz yeterlidir; mobil istemcileri App Store veya Play Store onay süreçlerine sokmanıza gerek kalmaz.
Web ve Mobil Ürünlerde Entegrasyon Zorlukları
MCP'yi doğrudan tüketiciye yönelik (B2C) bir web veya mobil uygulamada kullanırken dikkat edilmesi gereken kritik başlıklar vardır. Bunların başında güvenlik ve yetkilendirme gelir. Masaüstü kullanımında Claude Desktop doğrudan kullanıcının yerel makinesinde çalıştığı için yerel dosyalara stdio üzerinden tam yetkiyle erişebilir. Ancak çok kullanıcılı bir web mimarisinde her istemcinin yalnızca kendi verisine erişmesini sağlayacak izolasyon katmanını kurmak zorunludur:
- Oturum İzolasyonu: SSE bağlantısı üzerinden gelen her JSON-RPC isteği, kullanıcının JWT veya oturum belirteciyle doğrulanmalı ve araçlar yalnızca oturum sahibinin veritabanı kapsamına erişebilmelidir.
- Hız Sınırlaması ve Token Bütçesi: LLM'ler döngüsel mantık hatalarına düşüp aynı aracı saniyeler içinde onlarca kez çağırabilir. MCP katmanında araç bazlı hız sınırlaması (rate limiting) uygulanmalıdır.
- Gecikme Yönetimi: SSE üzerinden kurulan iki yönlü akış, mobil ağlarda bağlantı kopmalarına duyarlıdır. İstemcinin araç yanıtını bekleme süresi optimize edilmeli ve gerektiğinde yerel önbellekler devreye sokulmalıdır.
Bana kalırsa mobil istemcilerin doğrudan uzak bir MCP sunucusuna bağlanması yerine, uygulamanın kendi backend gateway'inin bir MCP istemcisi gibi davranması ve LLM ile olan etkileşimi yönetmesi çok daha kontrollü bir mimari sunar. Böylece modelin çağırmak istediği tehlikeli işlemler (para transferi, hesap silme vb.) backend tarafında bir 'insan onay mekanizması' (human-in-the-loop) süzgecinden geçirilebilir.
Bakım Kolaylığı ve Sonuç
El ile oluşturulmuş kırılgan sarmalayıcılardan standart bir MCP mimarisine geçmek, başlangıçta fazladan bir sunucu katmanı yönetme maliyeti getirse de, orta ve uzun vadede teknik borcu ciddi oranda düşürür. Model sağlayıcılarının sürekli değişen API kontratlarını takip etmek yerine, sisteminizi tek bir açık standart etrafında modellemiş olursunuz. Garmin örneğinde gördüğümüz gibi, topluluk tarafından yazılmış bir sunucuyu uygulamanıza tak-çıkar mantığıyla entegre edebilir veya kendi dahili servislerinizi tek seferde tüm LLM ekosistemine uyumlu hale getirebilirsiniz. Bir sonraki aşamada uygulamanızın en sık kullanılan üç harici veri kaynağını listeleyip, bunları standart bir MCP aracı olarak soyutlamayı denemek mimarinin getireceği esnekliği bizzat gözlemlemek için iyi bir başlangıç olabilir.