29 Ağu 2025

24 dk okuma

MCP Sunucu Mimarisi: State Yönetimi, Güvenlik ve Tool Orkestrasyonu

MCP Sunucu Mimarisi: State Yönetimi, Güvenlik ve Tool Orkestrasyonu

Production'da gerçekten çalışan bir MCP sunucusu inşa etmek ile sırf Github'a atıp dev portfolyonuzu havalı göstermek arasında ciddi bir fark var. Demo değil, proof-of-concept değil: gerçek agentic workflow'ları taşıyan, karmaşık konuşmalar boyunca state'ini koruyan ve LLM'iniz tool orkestrasyonunda "yaratıcı" davranmaya karar verdiğinde dağılmayan bir sistemden bahsediyoruz.

Bu sistemleri yıllarca büyük ölçekte kuran ekipleri izledikten (ve sabahın 2'sinde, sistemler kaçınılmaz olarak ilginç şekillerde bozulduğunda hata ayıklarken onları gördükten) sonra, "çalışan bir MCP sunucusu" ile "kurumsal düzeyde MCP altyapısı" arasındaki fark netleşiyor. Bu fark, API çağırabilen bir chatbot ile GDPR uyumluluğunu koruyan, Bizans tipi hataları yöneten ve bir yandan da güvenlik ekiplerini memnun tutmayı başaran, çok adımlı workflow'ları orkestre eden akıllı bir gateway arasındaki fark kadar büyük.

Gerçek şu: modern AI agent'lar yalnızca API çağrısı yapmakla kalmıyor. Onlarca etkileşim boyunca konuşma bağlamını korumaları, deneyimli dağıtık sistem mühendislerini bile zorlayacak karmaşık workflow'ları orkestre etmeleri ve yol boyunca keşfettiklerine göre yeteneklerini dinamik olarak uyarlamaları gerekiyor. Stateless mikroservisler ve basit istek-yanıt pattern'lerinden oluşan geleneksel oyun kitabı, agent'ınızın beş tur önce ne olduğunu hatırlaması gereken ve aynı anda paralel tool çalıştırmaları koordine ettiği anda tamamen çöküyor.

Bu kapsamlı teknik analiz, sofistike, stateful ve dayanıklı MCP sunucuları inşa etmek için blueprint düzeyinde bir rehber sunuyor. Bunlar dedenizin API sunucuları değil. Modern AI MCP sunucuları, LLM tabanlı agent'lar ile organizasyonunuzun bağımlı olduğu geniş gerçek dünya servisleri ekosistemi arasında stratejik olarak konumlanan akıllı gateway'ler olarak çalışıyor.

Tanık olduğumuz temel paradigma değişimi şu: geleneksel, prosedürel API etkileşimlerinden, daha sofistike, niyet tabanlı bir modele geçiş. Düşük seviyeli CRUD endpoint'lerine basit, stateless API çağrıları yapmak yerine, bir MCP sunucusu kullanan AI agent, "getSpaceActivity" gibi karmaşık işlemleri kapsayan üst düzey "tool"'ları çağırabiliyor ve böylece kullanıcı niyetini doğrudan anlamlı eylemlere çeviriyor.

Buradaki zorluk -ki hiç de küçük değil- bu sunucuları, birden fazla tur boyunca konuşma state'ini koruyacak, karmaşık çok adımlı workflow'ları güvenilir biçimde orkestre edecek ve mevcut API'lerle sorunsuzca entegre olacak şekilde tasarlarken, aynı zamanda sağlam bir güvenlik ve gizlilik uyumluluğu sağlamaktan geçiyor.

Bu doküman, mimarların kurumsal düzeyde implementasyonlar oluşturmak için çözmesi gereken üç kritik zorluk etrafında organize edilmiş, kapsamlı mimari pattern'ler sunuyor:

  1. Çok Turlu Workflow'lar için State Yönetimi: Bir dizi kullanıcı etkileşimi boyunca bağlamı ve veriyi koruyacak modeller tasarlamak; anlamlı, konuşma temelli her workflow için kritik bir gereksinim
  2. Planner Tool Orkestrasyon Pattern'leri: Karmaşık kullanıcı hedeflerine ulaşmak için birden fazla tool çağrısını sıralayan, basit ve reaktif karar vermenin ötesine geçen güvenilir ve verimli pattern'ler tasarlamak
  3. Dinamik Yetenek Kompozisyonu: Bir agent'ın yeteneklerinin anında genişletilebildiği veya değiştirilebildiği, tool'ların güçlü, ortaya çıkan (emergent) workflow'lar oluşturmak üzere bir araya getirilebildiği mimariler kurmak

Her pattern birden fazla açıdan inceleniyor: security-by-design, uyumluluk (GDPR ve CCPA'nın açıkça ele alınmasıyla), performans karakteristikleri ve implementasyon karmaşıklığı. Platform-agnostik ilkeler, ağırlıklı olarak bir Python/FastAPI stack'inde gösterilen, konteynerleştirilmeye ve Kubernetes üzerinde dağıtılmaya uygun somut, uygulanabilir örneklerle anlatılıyor; bu da modern, cloud-native bir yaklaşımı yansıtıyor.

Mevcut Protokoller ve Standartlarla Entegrasyon

Sunulan mimari pattern'ler, LLM'lerin konuşma temelli, niyet odaklı dünyasıyla mevcut kurumsal servislerin prosedürel, kaynak odaklı dünyası arasında köprü kuruyor. MCP sunucusu öncelikle OpenAPI/Swagger ve gRPC gibi standartlarla tanımlanan downstream servislerle arayüz oluşturuyor.

gRPC entegrasyonları için MCP sunucusu, protocol buffer'lar üzerinden tanımlanan servislerle etkileşime girerek yüksek performanslı, güçlü tipli iletişim sağlayabiliyor. Bir MCP tool sistemi için tipik bir gRPC servis tanımı; tool kaydı, streaming destekli çalıştırma ve yetenek keşfi gibi kabiliyetleri kapsıyor:

Protocol Buffers

service MCPToolService {
  // Tool registration
  rpc RegisterTool(ToolSpec) returns (RegistrationResult) {
    option (google.api.http) = {
      post: "/v1/tools"
      body: "*"
    };
  }
  // Tool execution with streaming support
  rpc ExecuteTool(stream ToolRequest) returns (stream ToolResponse);
  // Capability discovery
  rpc ListCapabilities(Empty) returns (CapabilityList) {
    option (google.api.http) = {
      get: "/v1/capabilities"
    };
  }
}

RegisterTool metodu bir ToolSpec kabul ediyor ve bir RegistrationResult döndürüyor; POST isteklerini "/v1/tools"'a eşleyecek şekilde yapılandırılmış. ExecuteTool metodu (hem istek hem yanıtta stream anahtar kelimesine dikkat edin) iki yönlü streaming kullanarak gerçek zamanlı, sürekli iletişime izin veriyor. ListCapabilities, GET "/v1/capabilities"'e eşlenen basit bir keşif mekanizması sunuyor.

Bu entegrasyon stratejisinin merkezinde şu ilke var: JSON Schema, kullanıcı niyetini API çağrılarına bağlayan ortak bir dil görevi görüyor. MCP tool tanımları, girdi ve çıktıları belirtmek için JSON Schema kullanıyor; bu da OpenAPI spesifikasyonlarıyla doğal olarak uyumlu bir standart. Bu uyum sayesinde geliştiriciler tool schema'larını genellikle mevcut API spec'lerinden doğrudan yeniden kullanabiliyor veya türetebiliyor, böylece tutarlılık sağlanıyor ve implementasyon basitleşiyor. Bir POST /sendEmail endpoint'i için OpenAPI schema'sı, bir sendEmail MCP tool'u için input schema olarak yeniden kullanılabiliyor ve mevcut servisleri AI agent'lara açmak için doğrudan bir yol sunuyor.

Bu eşleme, iki standardı birbirine bağlayacak şekilde formalize edilebiliyor:

YAML

# OpenAPI operation to MCP tool transformation
openapi: 3.1.0
paths:
  /analyze:
    post:
      operationId: analyzeText  # Becomes MCP tool name
      x-mcp-tool:
        category: analysis
        pipeability:
          accepts: ["text/plain", "application/json"]
          produces: ["application/json"]
        security:
          minimum_role: data-analyst
      requestBody:
        content:
          application/json:
            schema:  # Becomes MCP inputSchema
              type: object
              properties:
                text:
                  type: string
                options:
                  type: object

operationId, MCP tool adı haline geliyor; özel x-mcp-tool uzantıları agent'a özgü metadata'yı (kategori, pipeability, güvenlik rolleri) tanımlıyor ve mevcut OpenAPI schema'sı doğrudan MCP inputSchema'sı haline geliyor.

Mimarinin Temel İlkeleri

Tanımlanan her pattern, security-by-design ve veri koruma zorunlulukları merceğinden değerlendiriliyor. MCP sunucuları, doğaları gereği kullanıcı verisini ve potansiyel olarak hassas bağlamı işliyor; bu yüzden en az ayrıcalık, veri minimizasyonu, şifreleme ve denetlenebilirlik ilkelerini en baştan uygulamak zorundalar. Güvenlik ve uyumluluk burada birinci sınıf mimari kısıtlar olarak ele alınıyor.

Doküman, GDPR ve CCPA gibi regülasyonların etkilerini açıkça tartışıyor ve mimari kararların bir uyumluluk açığı yaratmadığından emin olmak için "Silme Hakkı"'nın her state yönetimi yaklaşımı içinde nasıl doğru uygulanacağını analiz ediyor.

Çok Turlu Etkileşimler için State Yönetimi Modelleri

Agentic AI'da Stateful Olma Zorunluluğu

Modern dağıtık sistemlerin mimarisi, merkezi bir gerilim üzerine kurulu: stateless servislerin ölçeklenebilirliği ve dayanıklılığı ile anlamlı, bağlama duyarlı etkileşimler için state'in zorunluluğu arasındaki gerilim. Her isteği önceki olaylardan habersiz, bağımsız bir işlem olarak ele alan stateless paradigma, basitliği, hata toleransı ve yatay ölçeklemenin kolaylığı sayesinde cloud-native ve mikroservis tasarımına uzun süredir hakim.

Ancak agentic AI sistemleri bu stateless ideali temelden sarsıyor. Çok turlu bir konuşma veya karmaşık, çok adımlı bir workflow, tanımı gereği stateful'dur. Sistemin etkili çalışabilmesi için kullanıcının niyetini, önceki tool çağrılarının sonuçlarını ve gelişen bağlamı hatırlaması gerekiyor. Geleneksel state yönetimi yaklaşımları, agentic AI'ın sayısız etkileşim boyunca korunan akıcı, konuşma temelli bağlam gereksinimini karşılamakta yetersiz kalıyor.

Bu durum, iki state türü arasında net bir mimari ayrım yapılmasını gerektiriyor:

  1. Kaynak State'i (Resource State): İş nesnelerinin kalıcı, kanonik state'i; genellikle veritabanlarında yönetilen ve RESTful API'ler üzerinden sunulan, sistemdeki "tek doğru kaynak"
  2. Uygulama State'i (Application State): Bir agent'ın oturum sırasında koruduğu geçici, konuşma temelli bağlam; kullanıcının hedefini, tool çağrılarından gelen ara sonuçları ve mevcut workflow'u tamamlamak için gereken her türlü bilgiyi kapsar

Gelişmiş bir MCP sunucusu için asıl mimari hedef, stateless ilkeleri terk etmek değil, bir hibrit mimari kurgulamaktır. Bu modelde kontrol düzlemi (agentic workflow'u orkestre eden MCP sunucusu) uygulama state'ini yönetirken, kaynak düzlemi (backend mikroservisleri) büyük ölçüde stateless kalır. Bu katmanlı yaklaşım, state yönetimi karmaşıklığını iyi tanımlanmış bir sınıra hapsederek, altta yatan sistem ölçeklenebilirliğinden ödün vermeden agentic etkileşimler için bir "stateful cephe" yaratır.

Model 1: Server-Side State Cache

Mimari Pattern Genel Bakış

Uygulama state'ini yönetmenin en doğrudan yolu, onu sunucuda özel, yüksek performanslı bir cache'de tutmaktır. Bu model, kullanıcıya özel state'i dağıtık Redis gibi hızlı bir datastore'da tutarak, bir kullanıcı oturumu boyunca tek doğru kaynağı sağlayacak şekilde state yönetimini merkezileştirir. State, güvenli, kullanıcıya özel bir session identifier'ı ile anahtarlanır.

Bu mimaride session state'i, kullanıcı kimliğiyle doğrudan bağlantılıdır. Standart bir OAuth 2.0 JSON Web Token'ından (JWT) gelen sub (subject) claim'i, kullanıcıya özel bir session cache'i için ideal birincil anahtar görevi görür ve kimliği doğrulanmış kullanıcılarla konuşma bağlamları arasında net, belirsizliğe yer bırakmayan bir eşleme yaratır.

Implementasyon ve Veri Akışı

Bu pattern için veri akışı net bir sıra izler:

  1. Kullanıcının client'ı, Authorization header'ında geçerli bir JWT ile birlikte MCP sunucusuna bir istek gönderir
  2. MCP sunucusu JWT'yi doğrular ve sub claim'ini çıkarır
  3. Sunucu, bu sub claim'ini kullanarak bir anahtar oluşturur (örn. session:{sub_claim_value}) ve mevcut session verisini almak için Redis'i sorgular
  4. Konuşma bağlamı yüklendikten sonra sunucu isteği işler, bu sırada bir veya daha fazla tool çağırabilir
  5. İşlem tamamlandıktan sonra sunucu, Redis'teki session verisini yeni bilgiyle günceller ve veri yaşam döngüsünü yönetmek için bir sona erme süresi (TTL) ayarlar
  6. Sunucu yanıtı client'a geri gönderir

FastAPI ve Redis kullanan somut bir Python implementasyonu, GDPR uyumluluğu değerlendirmeleri de dahil olmak üzere çok kiracılı (multi-tenant) session yönetimini gösteriyor:

Python

# FastAPI with Redis Multi-Tenant Session Manager
import uuid
import json
from datetime import datetime
import redis.asyncio
class TenantAwareSessionManager:
    def __init__(self, redis_pool: redis.asyncio.ConnectionPool):
        self.redis = redis_pool
        self.session_timeout = 1800  # 30 minutes
    async def create_session(self, oauth_sub: str, tenant_id: str) -> str:
        session_id = str(uuid.uuid4())
        session_key = f"sessions:{tenant_id}:{oauth_sub}:{session_id}"
        session_data = {
            "user_id": oauth_sub,
            "tenant_id": tenant_id,
            "created_at": datetime.utcnow().isoformat(),
            "conversation_state": {},
            "active_tools": []
        }
        async with self.redis.client() as conn:
            await conn.hset(session_key, mapping=session_data)
            await conn.expire(session_key, self.session_timeout)
            # Maintain user session index for GDPR compliance
            await conn.sadd(f"user_sessions:{oauth_sub}", session_key)
        return session_id

Güvenlik Analizi

Çok kiracılı uygulamalarda session depolama için paylaşımlı bir cache kullanmak, kritik güvenlik zorlukları doğurur: sıkı bir veri kiracılığı (data tenancy) ayrımını garanti etmek. Session yönetimindeki bir bug, bir kullanıcının verisinin başka birinin bağlamına sızmasına neden olabilir.

Redis'te kiracı izolasyonunu sağlamak için üç temel mimari pattern var, her birinin kendine has ödünleşimleri var:

  1. Key Prefixing (Düşük İzolasyon): Tüm kiracılar tek bir Redis veritabanını paylaşır. Uygulama mantığı her anahtarın önüne benzersiz bir tenant ID ekler (örn. tenant_123:session:user_abc). En basit ve en maliyet-etkin yöntem, ama en zayıf izolasyonu sunar; tamamen uygulama koduna dayanır.
  2. Kiracı Başına Veritabanı (Orta İzolasyon): Redis, tek bir instance içinde birden fazla mantıksal veritabanına izin verir. Her kiracı kendi veritabanını alır. Daha güçlü mantıksal ayrım sağlar ve Redis ACL'leri kimlik bilgilerini belirli veritabanlarıyla sınırlayabilir. Ancak kiracılar yine de compute ve bellek kaynaklarını paylaşır, bu da onları "gürültülü komşu" sorununa karşı savunmasız bırakır.
  3. Kiracı Başına Instance (Yüksek İzolasyon): Her kiracı kendi Redis instance'ını veya cluster'ını alır. Hem veri hem performans açısından en yüksek izolasyon derecesini sunar, ama operasyonel karmaşıklık ve maliyet açısından çok daha ağırdır.

Kiracılığın ötesinde, sağlam güvenlik için belirli teknik kontroller de gereklidir:

  • Sıkı key namespace ayrımı (örn. tenant:{tenantId}:session:{sessionId}:data)
  • Kullanıcıya özel key pattern kısıtlamalarını zorlayan Redis ACL'leri
  • Aktarım halindeki veri için TLS 1.3, bekleyen veri için AES-256 kullanan kapsamlı şifreleme

Session state'ini merkezileştirmek, klasik web güvenlik açıklarını da bertaraf etmeyi gerektirir:

  • Session Fixation: Saldırgan, kullanıcıyı kendisinin bildiği bir session ID'yi kullanmaya kandırır. Önleme: başarılı kimlik doğrulamanın hemen ardından yeni, tahmin edilemez session ID'leri üretmek.
  • Session Hijacking: Saldırgan, bir kullanıcı gibi davranmak için geçerli bir session ID'yi çalar. Azaltma: session identifier'ları için güvenli, HttpOnly cookie'ler, zorunlu HTTPS, otomatik session zaman aşımları ve session ID'leri için kriptografik olarak güvenli rastgele sayı üreteçleri.

Uyumluluk Analizi (GDPR/CCPA)

Konuşma geçmişini ve kullanıcı tarafından üretilen içeriği depolayarak, server-side cache bir Kişisel Bilgi (PI) deposu haline gelir ve doğrudan GDPR ve CCPA gibi regülasyonların kapsamına girer. Bu, MCP sunucusunu bir veri sorumlusu veya veri işleyen konumuna getirir ve önemli uyumluluk yükümlülükleri doğurur.

Mimari, temel veri sahibi haklarını desteklemek zorundadır:

Erişim ve Taşınabilirlik Hakkı: Sistem, tam session geçmişini alma ve dışa aktarma mekanizmaları sunmalıdır. Veri OAuth sub claim'i ile anahtarlandığından, bu identifier bu tür talepleri karşılayabilir.

Silme Hakkı ("Unutulma Hakkı"): Talep üzerine sistem, cache'lenmiş kopyalar ve türetilmiş state dahil olmak üzere, bir kullanıcının sub claim'iyle ilişkili tüm session verisini kalıcı olarak silmelidir. Sağlam bir implementasyon, tüm kişisel veriyi izlemeyi ve onu temizlemek için bir arayüz sunmayı gerektirir:

Python

async def handle_gdpr_erasure(self, oauth_sub: str, tenant_id: str):
    # Identify all user data across tenants
    pattern = f"*{oauth_sub}*"
    keys_to_delete = []
    async with self.redis.client() as conn:
        # Scan for all user keys (cursor-based for large datasets)
        cursor = 0
        while True:
            cursor, keys = await conn.scan(cursor, match=pattern, count=1000)
            keys_to_delete.extend(keys)
            if cursor == 0:
                break
        # Batch deletion with audit trail
        if keys_to_delete:
            # Archive audit log before deletion
            audit_entry = {
                "action": "gdpr_erasure",
                "user": oauth_sub,
                "keys_deleted": len(keys_to_delete),
                "timestamp": datetime.utcnow().isoformat()
            }
            await conn.setex(
                f"audit:erasure:{uuid.uuid4()}",
                7 * 24 * 3600,  # 7 day retention for audit
                json.dumps(audit_entry)
            )
            # Execute deletion
            await conn.delete(*keys_to_delete)

Veri minimizasyonu ve depolama sınırlaması ilkeleri kritik önemdedir. Redis'in TTL özelliği, saklama politikalarını uygulamak için mükemmel bir teknik kontrol sunar. Her session anahtarına TTL ayarlamak (gösterilen 30 dakikalık zaman aşımı gibi), eski, pasif session verisinin otomatik olarak silinmesini sağlar. Sistem yalnızca bir sonraki tur için kesinlikle gerekli olanı depolamalıdır: yeterli olduğunda tüm dokümanlar yerine doküman özetlerini cache'lemek gibi.

Performans ve Ölçeklenebilirlik

Bu model verimli performans karakteristikleri sunar:

  • Redis cluster'larında session işlemleri için tipik latency 5ms'nin altında (p99)
  • Redis sharding üzerinden yatay ölçeklenebilirlik
  • Metadata için session başına yaklaşık 2KB'lık düşük bellek ayak izi
  • Tipik cloud dağıtımlarında milyon işlem başına yaklaşık 0,08 dolar maliyet

Ancak bu yaklaşım yatay ölçeklemeyi karmaşıklaştırabilir. Bellek içi cache kullanmak, ya session affinity (tüm kullanıcı isteklerini aynı sunucu instance'ına yönlendirmek) ya da tüm instance'lar tarafından erişilebilen Redis/Memcached gibi bir dağıtık cache gerektirir. Session affinity, yük dengelemeyi karmaşıklaştırır ve dayanıklılığı azaltır. Redis gibi harici store'lar bunu hafifletir, ama her tool çağrısına bir network hop'u ekler. Kubernetes veya AWS Lambda üzerindeki cloud-native dağıtımlar için, stateless uygulama instance'larını korumak ve yüksek ölçeklenebilirlik elde etmek adına dışsallaştırılmış, dağıtık cache tercih edilir.

Bu model, LLM'nin tekrar tekrar görmemesi gereken karmaşık, hassas veya büyük state'i korumak için mükemmeldir. Kurumsal asistanlar veya finansal co-pilot'lar gibi, veri üzerinde sıkı kontrol gerektiren durumlar için idealdir.

Model 2: Client-Side State via Ephemeral Pointers

Mimari Pattern Genel Bakış

Server-side state yönetimine bir alternatif, stateless RESTful mimari ilkelerine daha yakın durur. Bu pattern'de sunucu, istekler arasında uygulama state'ini tutmaz. Bunun yerine, stateful veriyi temsil etmek için imzalı, kısa ömürlü kaynak URI'ları ("pointer'lar") kullanır. Bu pointer'lar client'a döndürülür ve client bağlamı korumak için sonraki isteklerine bunları dahil eder. Bu, gerçek bir stateless'lik değil, state'in dışsallaştırılmasıdır; sunucu bellek ayak izini önemli ölçüde azaltırken altyapı karmaşıklığını güvenlik karmaşıklığıyla takas eder.

Implementasyon ve Veri Akışı

Bu model uygulama state'ini dışsallaştırarak, konuşma bağlamını izleme sorumluluğunu sunucudan client'a kaydırır. Veri akışı tipik olarak şunları içerir:

  1. Kullanıcı prompt'u, geçici bir kaynak oluşturan bir tool çağrısına yol açar (örn. S3'te bir doküman taslağı depolamak)
  2. Sunucu kaynağı oluşturur ve onu tanımlayan benzersiz, güvenli bir URI olan geçici resource_link'i döndürür
  3. Client, bu resource_link'i bir sonraki prompt bağlamına dahil eder (bazı MCP client'ları bunu UI'dan gizler)
  4. LLM, daha önce oluşturulan kaynak üzerinde işlem yapmak için sonraki tool çağrılarında bu URI'yi kullanır

Güvenli bir implementasyon, state'i S3 gibi bir backend'de depolamayı, geçici erişim için pre-signed URL'ler üretmeyi ve bütünlük doğrulaması için HMAC imzaları eklemeyi içerir:

Python

from cryptography.hazmat.primitives import hashes, hmac
import base64
from datetime import datetime, timedelta
import json
import uuid
# Assume S3Client is a pre-configured S3 client interface
class EphemeralStatePointer:
    def __init__(self, secret_key: bytes, storage_backend: S3Client):
        self.secret_key = secret_key
        self.storage = storage_backend
    def create_state_pointer(
        self,
        session_id: str,
        state_data: dict,
        expires_in: int = 900  # 15 minutes
    ) -> dict:
        # Store state in object storage
        state_key = f"state/{session_id}/{uuid.uuid4()}.json"
        self.storage.put_object(
            Bucket="mcp-state-bucket",
            Key=state_key,
            Body=json.dumps(state_data),
            ServerSideEncryption="AES256"
        )
        # Generate signed URL with security constraints
        presigned_url = self.storage.generate_presigned_url(
            'get_object',
            Params={
                'Bucket': 'mcp-state-bucket',
                'Key': state_key,
                'ResponseContentType': 'application/json'
            },
            ExpiresIn=expires_in,
            HttpMethod='GET'
        )
        # Add integrity signature
        h = hmac.HMAC(self.secret_key, hashes.SHA256())
        h.update(presigned_url.encode())
        signature = base64.b64encode(h.finalize()).decode()
        return {
            "resource_link": presigned_url,
            "signature": signature,
            "expires_at": (datetime.utcnow() + timedelta(seconds=expires_in)).isoformat(),
            "session_id": session_id
        }

Güvenlik Analizi

Korumasız kaynak URI'ları önemli güvenlik açıklarıdır. Pointer'lar capability token'lar gibi davranır; tahmin edilemez, zaman sınırlı ve kapsamı belirlenmiş olmaları gerekir. Bunları etkili şekilde güvenceye almak için iki temel pattern var:

  1. İmzalı URL'ler: resource_link, kriptografik bilgi (sona erme zaman damgası ve imza) içerir. Sunucu, paylaşılan bir gizli anahtar kullanarak imzayı doğrular ve veritabanı sorgusu yapmadan gerçekliği teyit eder. AWS S3 Presigned URL'lerine benzer, geçici, izin kapsamı belirlenmiş erişim için idealdir.
  2. Kısa Ömürlü Access Token'lar: Kaynak erişimini URI'den ayırır. Client kısa ömürlü bir token alır (örn. 5-15 dakika geçerlilik süreli bir JWT) ve kaynak pointer'ları içeren istekler için bunu Authorization: Bearer header'ına dahil eder.

Pointer hijacking'i önlemek için birkaç mekanizma kullanılabilir:

  • Redis üzerinden izlenen Tek Kullanımlık Token'lar
  • Opsiyonel kaynak IP bağlama
  • MD5/SHA256 içerik bütünlüğü doğrulaması
  • Pointer geçerliliği için 5-15 dakikalık kısa zaman pencereleri

Bu model için kritik best practice'ler:

  • İmzalı URL'ler ve access token'lar için mümkün olan en kısa yaşam süresi
  • Tüm iletişimin şifrelenmiş HTTPS kanalları üzerinden yapılması
  • Pointer'ın verdiği erişimin yalnızca gereken belirli eylemlerle sınırlandırılması (en az ayrıcalık)
  • Sunucunun her pointer'ı, onu oluşturan kullanıcı/session ile eşleştirerek kullanıcılar arası erişimi önlemesi

Uyumluluk Analizi

Geçici pointer modeli, sunucularda uzun vadeli kişisel veri depolamayı azaltarak uyumluluğa yardımcı olur. Veri daha geçici olduğundan, GDPR'ın depolama sınırlaması ilkesine uyumu kolaylaştırır. Önemli bir avantaj: LLM'lere daha az PII maruziyeti. Tüm tıbbi kayıtları ileri geri göndermek yerine, model resource://record/457 gibi pointer'lar görür; bu da prompt bağlamı üzerinden akan ham hassas veriyi ve model sağlayıcılarına istenmeden yapılan ifşayı en aza indirir.

Ancak Silme Hakkı'nı uygulamak, pointer'ların referans verdiği object store'lardaki temel veriyi izlemek ve silmek için hâlâ sağlam mekanizmalar gerektirir. Kullanıcılar silme talep ettiğinde, sunucular aktif pointer'ları geçersiz kılmalı ve ilişkili veriyi temizlemelidir.

Ölçeklenebilirlik ve Performans

Bu pattern önemli ölçeklenebilirlik avantajları sunar:

  • Büyük payload'lar için server-side bellek tüketimini %90'a kadar azaltır
  • Coğrafi dağıtım için CDN'lerle yüksek uyumluluk
  • Sunucu instance'larının basit, stateless yatay ölçeklemesi
  • İmza işlemleri nedeniyle biraz daha yüksek olan, milyon işlem başına yaklaşık 0,12 dolar maliyet

Ancak sorguları verimli şekilde işlemek için performanslı pointer store'ları (dağıtık cache veya veritabanı) gerektirir ve istek başına kriptografik token doğrulaması veya yenileme döngülerinden kaynaklanan bir gecikme (latency) ortaya çıkabilir.

Bu model, bireysel etkileşimlerin server-side nesneler oluşturduğu veya değiştirdiği (doküman düzenleme, veri analizi) yüksek trafikli, kaynak odaklı görevler için idealdir. Aynı zamanda dinamik tool etkinleştirme ve ikili (binary) veriyle entegrasyon için de anahtar bir modeldir.

Model 3: Stateful Content Payloads

Mimari Pattern Genel Bakış

Üçüncü bir pattern, tüm session state'ini doğrudan yapılandırılmış API yanıtları içinde kodlamayı içerir; örneğin MCP tool yanıtlarındaki structuredContent alanları gibi. Client, bu tüm state nesnesini bir sonraki isteğin payload'ında geri gönderir ve konuşmanın kendisini state taşıyıcısı haline getirir.

Bu yaklaşım, ölçeklenebilir, dayanıklı sistemlerde temelden bir anti-pattern'dir ve bir "mimari kod kokusu" olarak değerlendirilmelidir. Şişkin, verimsiz istek ve yanıtlar yaratarak temel RESTful ilkelerini ihlal eder ve client ile sunucu arasında sıkı, kırılgan bir bağımlılık kurar.

OpenAI Structured Outputs ile Implementasyon

Sorunlarına rağmen bu pattern, ileri geri aktarılan state'i tanımlamak için yapılandırılmış çıktı modelleri (Python'da Pydantic) kullanılarak uygulanabilir:

Python

from pydantic import BaseModel
from typing import List, Optional
class ConversationState(BaseModel):
    session_id: str
    turn_count: int
    context_summary: str
    active_tools: List[str]
    user_preferences: dict
    planning_state: Optional[dict]
class MCPStructuredResponse(BaseModel):
    content: str
    conversation_state: ConversationState
    resource_links: List[str]
    next_actions: List[str]

Kötüye kullanımı önlemek için, state payload'ları client'a döndürülmeden önce bütünlük açısından imzalanmalı (örn. HMAC-SHA256) ve sonraki isteklerde doğrulanmalıdır.

Kullanım Alanları ve Ciddi Sınırlamalar

Uygun kullanım alanları son derece dardır: state'in minimal, hassas olmayan ve anında geçici olduğu tek turlu "state geçişleri". Örneğin bir tool'un, bir sonraki mantıksal adımı işaret etmek için {"status": "confirmation_pending"} döndürmesi gibi.

Bu sınırlı senaryonun ötesinde, sınırlamalar ciddileşir:

  • Zayıf Ölçeklenebilirlik: Konuşma state'i büyüdükçe payload'lar hantallaşır, aşırı bant genişliği, bellek ve LLM bağlamı tüketir. Sert bir sınır olarak maksimum 64KB'lık state payload'u zorunlu kılınmalıdır.
  • Güvenlik Riskleri: Sunucunun iç state'ini client'lara açmak saldırı yüzeyini önemli ölçüde artırır, hassas bilgi sızdırabilir ve doğrulama hatalıysa kurcalamaya (tampering) açıktır. Client'a görünen state, dikkatli bir PII redaksiyonu gerektirir. Payload'lardaki herhangi bir veri LLM prompt'larına ve potansiyel olarak üçüncü taraf model sağlayıcılarına gider, bu da veri işleme kurallarını ihlal edebilir.
  • Bakım Karmaşıklığı: State mantığının istek-yanıt döngülerine dağıldığı, karmaşık, hata ayıklaması zor koda yol açar. Schema versiyonlama ve evrim zorlukları getirir.

State Yönetimi için Karar Çerçevesi

Doğru state yönetimi modelini seçmek, güvenlik, performans, karmaşıklık ve uyumluluk gereksinimleri arasında dikkatli bir denge gerektiren kritik bir mimari karardır.

Karşılaştırmalı Matris

Üst düzey ödünleşim özeti:

Faktör Server-Side Cache Client Pointer'ları Stateful Payload'lar
Güvenlik ⭐⭐⭐⭐⭐ ⭐⭐⭐ ⭐⭐
Uyumluluk ⭐⭐⭐⭐⭐ ⭐⭐⭐ ⭐⭐
Performans ⭐⭐⭐⭐ ⭐⭐⭐ ⭐⭐⭐⭐⭐
Ölçeklenebilirlik ⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐
Karmaşıklık ⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐

Detaylı niteliksel karşılaştırma:

Kriter Server-Side State Cache Pointer'lar Üzerinden Client-Side State Stateful Content Payload'ları
Güvenlik Duruşu Yüksek. Merkezi kontrol, sağlam kiracılık ve session yönetimi gerektirir. Orta. Dağıtık güven modeli; güvenlik kriptografik token/imza doğrulamasına dayanır. Düşük. İç state'i client'a açar, geniş saldırı yüzeyi.
Uyumluluk Yükü Yüksek. Session geçmişinde PII'yi doğrudan yönetir, tam GDPR/CCPA implementasyonu gerektirir. Düşük. State geçici kaynaklara bağlı, zamanla daha az PII depolar. Orta. PII payload'larda görünebilir ama kalıcı olarak depolanmaz.
Ölçeklenebilirlik Orta. Yatay olarak ölçeklenebilir, ama merkezi session store'unda darboğaz oluşabilir. Yüksek. Server-side session affinity olmadan tamamen yatay ölçeklenebilir. Çok Düşük. Büyük payload'lar önemli network ve işleme yükü yaratır.
Latency Profili Düşük. State alma tipik olarak tek, hızlı bir bellek içi sorgu. Orta. Token doğrulama veya yenileme döngülerinden latency ortaya çıkabilir. Yüksek. Daha büyük istek/yanıt boyutları nedeniyle artan latency.
Implementasyon Karmaşıklığı Orta. Stateful altyapı ve veri kiracılığı mantığının yönetilmesini gerektirir. Yüksek. Karmaşık client-side token yönetimi ve sağlam, istek başına kriptografik güvenlik gerektirir. Düşük (Başlangıçta). Basit durumlar için aldatıcı derecede basit, ama yüksek bakım karmaşıklığına yol açar.
En Uygun Olduğu Yer Yüksek güvenlik ihtiyacı ve hassas veri içeren karmaşık, uzun süreli agentic workflow'lar. Etkileşimlerin server-side nesneler oluşturduğu veya değiştirdiği yüksek trafikli, kaynak odaklı görevler. Production için önerilmez. Yalnızca önemsiz, tek turlu state geçişleri için kullanın.

Karar Akış Şeması

Kod snippet'i

graph TD
    A[State Management Decision] --> B{Data Size?}
    B -->|<10KB| C{Security Requirements?}
    B -->|>10KB| D[Client-Side Pointers]
    C -->|High| E{Compliance Needs?}
    C -->|Standard| F[Stateful Payloads]
    E -->|GDPR/CCPA| G[Server-Side Cache]
    E -->|None| H[Evaluate Performance]
    H -->|Low Latency| G
    H -->|Scalability| D

Seçim için Yol Gösterici İlkeler

Sonuçta seçim, şu yol gösterici ilkeler tarafından yönlendirilmelidir:

  • Veri hassas veya büyükse, payload'lara gömmekten kaçının (Model 3)
  • Server-side caching (Model 1), uyumluluk için en fazla kontrolü sunar; tüm session'ı kalıcı kılan karmaşık state için idealdir
  • Pointer tabanlı state (Model 2), geçici, kaynak odaklı veri için stateless, yüksek ölçeklenebilir mimarilerde öne çıkar
  • Birçok gerçek dünya sisteminde hibrit yaklaşımlar en uygunudur (LLM konuşmasında minimal identifier'lar, toplu veri server-side)
  • En üst ilke: en az veri maruziyeti — veriyi yalnızca gerekli olduğu yerde ve gerektiği süre kadar tutmak

"Planner Tool" Orkestrasyon Pattern'i

MCP workflow'ları karmaşıklaştıkça, çok adımlı görevleri güvenilir biçimde orkestre etmek anahtar bir zorluk haline geliyor. Tool çağrılarının orkestrasyonu, bir MCP sunucusunun merkezi işlevlerinden biridir. Planner tool pattern'i, paradigmayı reaktif, adım adım zincirlemeden daha proaktif, önce-planla-sonra-çalıştır yaklaşımlarına kaydırıyor.

Proaktif Planlama ve Reaktif Zincirleme

Tool çağrılarını sıralamak için iki baskın pattern ortaya çıktı:

  1. Reaktif Zincirleme (ReAct): LLM'in önceki sonuçları aldıktan sonra bir sonraki eylemine karar verdiği klasik "agent döngüsü" veya "prompt chaining" yaklaşımı. Her adım kendi içinde tamamlanmış bir düşünme, eylem, gözlem döngüsüdür. Gerçek zamanlı strateji uyarlamasına izin vererek maksimum esneklik sunar, ama bu esneklik güvenilirlikten, verimlilikten ve hata ayıklanabilirlikten ödün verebilir.
  2. Proaktif Planlama (Plan-then-Execute): "Routine" gibi ileri düzey framework'lerde görülen bu yaklaşım, üst düzey planlamayı düşük düzey çalıştırmadan ayırır. Agent önce kullanıcının hedefini analiz eder ve (genellikle yapılandırılmış bir nesne olarak) eksiksiz, çok adımlı bir plan üretir; ardından deterministik bir executor modülü bu planı çalıştırarak daha fazla öngörülebilirlik, istikrar ve kontrol sağlar.

Ödünleşim Analizi

Performans metrikleri değişkenlik gösterse de, genel ödünleşimler tutarlıdır:

Metrik Proaktif Planlama Reaktif Zincirleme Hibrit Yaklaşım
Güvenilirlik %85 başarı oranı %70 başarı oranı %92 başarı oranı
Token Maliyeti 5.000 peşin + 2.000 çalıştırma Adım başına 500 × N 3.000 + adaptif
Latency (ilk sonuç) 8-12 saniye 2-3 saniye 4-5 saniye
Toplam Çalıştırma Süresi 45 saniye 60-90 saniye 40 saniye
Hata Ayıklanabilirlik Mükemmel Orta İyi
Uyarlanabilirlik Zayıf Mükemmel Çok İyi

Niteliksel analiz farkları öne çıkarıyor:

Proaktif planlama genellikle daha yüksek güvenilirlik ve doğruluk sunar: model görevin tamamını bir arada değerlendirdiği için daha tutarlı çözümlere ulaşır. Token maliyeti ve latency açısından daha verimlidir (pahalı LLM yalnızca planlama için bir kez çağrılır, ardından potansiyel olarak daha ucuz bir çalıştırma gelir). Ortaya çıkan plan nesnesi, ortaya çıkan (emergent), opak reaktif akıl yürütmeden çok daha kolay hata ayıklanabilen, yapılandırılmış, denetlenebilir bir çıktıdır. Çalıştırmadan önce governance ve politika uygulama kontrol noktaları sağlar.

Buna karşılık reaktif zincirleme üstün esneklik ve uyarlanabilirlik sunar: agent'lar yeni bilgiye göre her adımda rota değiştirebilir. Ancak bu, tekrarlanan LLM çağrılarından kaynaklanan daha yüksek token maliyetleri pahasına gelir ve agent'ın akıl yürütmesi ortaya çıkan (emergent) ve opak olduğundan hata ayıklamak zordur, bu da hataları yeniden üretmeyi güçleştirir.

Güvenlik Mimarisi Olarak Proaktif Planlama

Kritik bir nokta: "Plan-then-Execute" pattern'i yalnızca bir orkestrasyon tercihi değildir; temel bir güvenlik mimarisidir. Tool'lar harici, potansiyel olarak güvenilmez veriyle etkileşime girmeden önce planı üretip "dondurarak", bu pattern LLM agent'lar için kontrol akışı bütünlüğü sağlar.

Reaktif modellerde, tool çıktısı -ki bu prompt injection saldırıları içerebilir- LLM'e bir sonraki eylemine karar vermeden önce doğrudan geri besleniyor ve bu da saldırganların workflow'ları ele geçirmesine izin verebiliyor. Proaktif modellerde ise güvenilmez veri yalnızca sonraki, zaten planlanmış eylemlerin parametrelerini etkileyebiliyor, eylemin kendisinin seçimini değil. Bu, prompt injection risklerini önemli ölçüde azaltıyor ve güvenli, güvenilir sistemler için esas teşkil ediyor.

Mimari Taslak ve Workflow

Proaktif planlamayı uygulamak, LLM'in karmaşık görevler için çağırdığı özel bir create_plan tool'unu içerir:

┌──────────────────────────────────────────────────────────────┐
│                    MCP Planner Tool System                   │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│  User Prompt                                                 │
│      ↓                                                       │
│  ┌─────────────┐    create_plan()    ┌──────────────┐        │
│  │ LLM Agent   ├────────────────────►│ Planner Tool │        │
│  └─────────────┘                     └──────┬───────┘        │
│                                             ↓                │
│                                     ┌───────────────┐        │
│                                     │ DAG Generator │        │
│                                     └───────┬───────┘        │
│                                             ↓                │
│                                    Plan Object (JSON)        │
│                                             ↓                │
│  ┌────────────────────────────────────────────────────────┐  │
│  │                    Execution Engine                    │  │
│  │  ┌───────────┐  ┌───────────┐  ┌───────────────┐       │  │
│  │  │ Scheduler │  │ Executor  │  │ State Manager │       │  │
│  │  └───────────┘  └───────────┘  └───────────────┘       │  │
│  └────────────────────────────────────────────────────────┘  │
│                               ↓                              │
│                        Tool Execution                        │
│                               ↓                              │
│                      Result Aggregation                      │
└──────────────────────────────────────────────────────────────┘

Uçtan uca workflow:

  1. Kullanıcı Prompt'u: Kullanıcı karmaşık, çok adımlı bir hedef verir (örn. "Geçen çeyreğin satış verisini analiz et, özet rapor oluştur, yöneticiye e-posta at")
  2. İlk LLM Çağrısı ve Planlama Tetiklemesi: Client, özel bir meta-tool olan create_plan(goal: string) da dahil olmak üzere mevcut tool'larla birlikte prompt'u LLM'e gönderir
  3. Planlama Tetiklemesi: LLM karmaşıklığı fark eder ve create_plan tool'unu çağırır
  4. Plan Üretimi: MCP sunucusunun create_plan implementasyonu (genellikle yoğun talimatlandırılmış bir LLM çağrısı kullanarak) hedefi bir tool çağrısı dizisine ayrıştırır, çıktıyı yapılandırılmış bir "Plan Nesnesi" olarak biçimlendirir
  5. Planın Dönüşü ve Çalıştırılması: Plan Nesnesi, create_plan sonucu olarak birincil LLM'e döner. Birincil LLM executor rolüne geçer, planı inceler ve tamamlanan görevlerin çıktılarını sonrakilerin girdisi olarak aktararak, belirtilen sırayla ilgili tool'ları tamamlanana kadar çağırır

Resmi Plan Nesnesi Spesifikasyonu

Proaktif planlamayı sağlam hale getirmek için create_plan çıktısı, katı, resmi bir spesifikasyona uymalıdır. "Plan Nesnesi", tüm workflow'u görevlerin bir Yönlü Çevrimsiz Grafiği (DAG) olarak temsil eden, makine tarafından okunabilir bir sözleşme görevi görür.

PlanObject için kapsamlı JSON Schema:

JSON

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "PlanObject",
  "description": "A structured representation of a multi-step execution plan for an AI agent.",
  "type": "object",
  "properties": {
    "plan_id": {
      "type": "string",
      "format": "uuid",
      "description": "A unique identifier for this execution plan."
    },
    "tasks": {
      "type": "object",
      "description": "A map of task IDs to task definitions.",
      "additionalProperties": {
        "$ref": "#/definitions/Task"
      }
    }
  },
  "required": ["plan_id", "tasks"],
  "definitions": {
    "Task": {
      "type": "object",
      "properties": {
        "tool_name": {
          "type": "string",
          "description": "The name of the tool to be executed for this task."
        },
        "description": {
          "type": "string",
          "description": "A human-readable description of the task's purpose."
        },
        "parameters": {
          "type": "object",
          "description": "A map of parameter names to values for the tool call. Values can be literals or references to outputs of other tasks.",
          "additionalProperties": true
        },
        "dependencies": {
          "type": "array",
          "description": "An array of task IDs that must be completed before this task can start.",
          "items": {
            "type": "string"
          }
        },
        "error_handling": {
          "type": "object",
          "properties": {
            "on_error": {
              "type": "string",
              "description": "The ID of a task to execute if this task fails."
            }
          }
        }
      },
      "required": ["tool_name", "parameters", "dependencies"]
    }
  }
}

Daha okunabilir alternatif YAML spesifikasyonu:

YAML

# Plan Object Schema (YAML for readability, converts to JSON)
PlanSpecification:
  version: "1.0.0"
  metadata:
    id: "plan-uuid"
    created_at: "2024-01-15T10:30:00Z"
    planner_version: "2.1.0"
  nodes:
    - id: "extract-data"
      type: "tool_execution"
      tool: "data_extractor"
      parameters:
        source: "${input.data_source}"
        format: "json"
      timeout: 30
      retry:
        max_attempts: 3
        backoff: "exponential"
    - id: "parallel-analysis"
      type: "parallel_group"
      children:
        - id: "sentiment-analysis"
          tool: "sentiment_analyzer"
          parameters:
            input: "${extract-data.output}"
        - id: "entity-extraction"
          tool: "entity_extractor"
          parameters:
            input: "${extract-data.output}"
    - id: "aggregate-results"
      type: "tool_execution"
      tool: "result_aggregator"
      dependencies: ["parallel-analysis"]
      parameters:
        sentiment: "${sentiment-analysis.output}"
        entities: "${entity-extraction.output}"
  error_handlers:
    - trigger: "node_failure"
      node_pattern: "*-analysis"
      action:
        type: "compensate"
        handler: "fallback_analyzer"
  edges:
    - from: "extract-data"
      to: "parallel-analysis"
      condition: "extract-data.status == 'success'"
    - from: "parallel-analysis"
      to: "aggregate-results"
      condition: "all_children_complete"

Temel spesifikasyon bileşenleri:

  • Görevler, Bağımlılıklar ve Paralellik: dependencies dizisi veya edges listesi DAG yapısını tanımlar. Aralarında karşılıklı bağımlılık olmayan görevler paralel çalışır (örn. sentiment-analysis ve entity-extraction, ikisi de extract-data'ya bağlı ama birbirine bağlı değil)
  • Parametre Referanslama ve Veri Zincirleme: "${extract-data.output}" veya {"$ref": "tasks.task_A.outputs.sales_data"} gibi bir sözdizimi kullanarak görevler arası veri akışını mümkün kılar; çalıştırma motorunun çıktıları girdi olarak yerine koymasına izin verir
  • Hata Yönetimi ve Koşullu Mantık: Plan'lar, error_handlers blokları veya daha basit on_error özellikleri üzerinden telafi edici eylemler ya da alternatif çalıştırma yolları tanımlayabilir

Implementasyon Pattern'leri

Proaktif planlama pattern'inin Python implementasyonu:

Python

from typing import List, Dict, Optional, Tuple
from dataclasses import dataclass
from enum import Enum
class TaskType(Enum):
    SEQUENTIAL = "sequential"
    PARALLEL = "parallel"
    CONDITIONAL = "conditional"
    LOOP = "loop"
@dataclass
class PlanNode:
    id: str
    tool_name: str
    parameters: Dict
    dependencies: List[str]
    error_handlers: List['ErrorHandler']
    retry_policy: Optional['RetryPolicy']
@dataclass
class PlanDAG:
    nodes: List[PlanNode]
    edges: List[Tuple[str, str]]
    metadata: Dict
class ProactivePlanner:
    def __init__(self, llm_client, tool_registry):
        self.llm = llm_client
        self.tools = tool_registry
    async def create_plan(self, user_prompt: str) -> PlanDAG:
        # Generate plan using LLM
        plan_prompt = f"""
        Create a detailed execution plan for: {user_prompt}
        Available tools: {self.tools.list_capabilities()}
        Output format: Directed Acyclic Graph with dependencies
        """
        raw_plan = await self.llm.generate_structured_output(
            prompt=plan_prompt,
            schema=PlanDAG
        )
        # Validate and optimize plan
        validated_plan = self.validate_dag(raw_plan)
        optimized_plan = self.optimize_execution_order(validated_plan)
        return optimized_plan
    def validate_dag(self, plan: PlanDAG) -> PlanDAG:
        # Check for cycles
        if self.has_cycles(plan):
            raise ValueError("Plan contains cycles")
        # Verify tool availability
        for node in plan.nodes:
            if not self.tools.is_available(node.tool_name):
                raise ValueError(f"Tool {node.tool_name} not available")
        return plan

Karşılaştırma için reaktif zincirleme implementasyonu:

Python

class ReactiveExecutor:
    def __init__(self, llm_client, tool_registry):
        self.llm = llm_client
        self.tools = tool_registry
        self.execution_history = []
    async def execute_reactive(
        self,
        initial_prompt: str,
        max_steps: int = 10
    ) -> dict:
        current_context = {"prompt": initial_prompt, "results": []}
        for step in range(max_steps):
            # Determine next action based on current context
            next_action = await self.llm.decide_next_action(
                context=current_context,
                available_tools=self.tools.list_available(),
                history=self.execution_history
            )
            if next_action.type == "complete":
                return {"status": "success", "results": current_context["results"]}
            # Execute chosen tool
            tool_result = await self.tools.execute(
                tool_name=next_action.tool,
                parameters=next_action.parameters
            )
            # Update context and history
            current_context["results"].append(tool_result)
            self.execution_history.append({
                "step": step,
                "action": next_action,
                "result": tool_result
            })
            # Check for errors and adapt
            if tool_result.status == "error":
                recovery_action = await self.plan_recovery(
                    error=tool_result.error,
                    context=current_context
                )
                if recovery_action:
                    current_context = recovery_action
                else:
                    return {"status": "failed", "error": tool_result.error}
        return {"status": "max_steps_reached", "results": current_context["results"]}

Dinamik Yetenek ve Kompozisyon Pattern'leri

Gelişmiş MCP sunucuları, yeteneklerini dinamik olarak genişletmeli ve tool'ların kusursuz workflow'lara dönüşecek şekilde bir araya getirilmesine izin vermelidir.

Dinamik Tool Kaydı

Mimari Gerekçe

Gerçek anlamda akıllı, uyarlanabilir agent'lar için yetenekler statik olamaz. Statik, önceden tanımlanmış tool listeleri, agent'ların bağlama göre konuşma ortasında yeni tool'lar edinmesi gereken senaryolar için yetersizdir. Örneğin, belirli bir veri kaynağına bağlandıktan sonra agent, o kaynağın kendine özgü schema'sını sorgulamak için dinamik olarak yeni tool'lar kazanmalıdır. Bu, MCP sunucusunu yalnızca bir tool çalıştırıcısı değil, işletim sistemlerinin yeni bağlanan donanım için sürücüleri dinamik olarak yüklemesine benzer bir yetenek yöneticisi olarak ele alan bir mimari gerektirir.

Mimari Bileşenler ve Akış

Dinamik mimari üç temel bileşen üzerine kuruludur:

  1. MCP Sunucusu: Agent'ın yaşam döngüsünü ve yeteneklerini yöneten merkezi orkestratör
  2. Global Tool Registry: Sistemin kullanabileceği tüm olası tool'ların tanımlarını içeren kalıcı store
  3. Session-Scoped Tool Registry: Belirli bir kullanıcı session'ıyla ilişkili, o an aktif olan tool alt kümesini tutan bellek içi cache veya kısa ömürlü kayıt

Dinamik kayıt süreci, yeni bağlama özgü tool'lar üreten ve kaydeden bir "factory" tool tarafından tetiklenir:

  1. Kullanıcı, agent'a bir veri kaynağına bağlanmasını talimatlandırır ve bu, connectToDataSource(source_id='production_db') gibi bir factory tool çağrısını tetikler
  2. MCP sunucusunun implementasyonu, belirtilen veri kaynağına kimlik doğrular
  3. Kaynağın schema'sını inceleyerek mevcut tabloları, view'leri, fonksiyonları belirler
  4. Schema'ya dayanarak, yeni, veri kaynağına özgü tool'lar (örn. query_customer_table) dinamik olarak üretir veya Global Tool Registry'den tanımları alır
  5. Yeni etkinleştirilen tool'lar, kullanıcının Session-Scoped Tool Registry'sine eklenir
  6. MCP sunucusu, client'a tamamlanmış güncel tool listesini sağlayan bir list_changed bildirimi gönderir

MCP Protokol Mekanizması: list_changed

MCP protokolü dinamik yeteneği açıkça destekler. Tool'larını değiştirebilen sunucular listChanged yeteneğini duyurur. Sunucu tool ekleyip çıkardığında, client'a notifications/tools/list_changed mesajı gönderir. Bunu alan client'ın, güncellenmiş tanımları almak için tools/list'i yeniden çağırması beklenir; bu da LLM'in yeni yeteneklerden haberdar olmasını sağlar (bildirim/yenileme döngüsünün client tarafından doğru şekilde işlenmesini gerektirir).

Implementasyon Detayları

Pattern'in Python implementasyonu:

Python

class DynamicToolRegistry:
    def __init__(self, discovery_backend: ServiceDiscovery):
        self.discovery = discovery_backend
        self.tools = {}
        self.capabilities = {}
        self.subscribers = []
    async def register_tool(
        self,
        tool_spec: ToolSpecification,
        security_context: SecurityContext
    ) -> dict:
        # Validate security credentials
        if not self.validate_security(tool_spec, security_context):
            raise SecurityException("Invalid tool credentials")
        # Register with service discovery
        service_id = await self.discovery.register_service(
            name=tool_spec.name,
            address=tool_spec.endpoint,
            metadata={
                "capabilities": tool_spec.capabilities,
                "version": tool_spec.version,
                "schema_url": tool_spec.schema_endpoint
            }
        )
        # Update internal registry and notify subscribers
        # ... implementation details ...
        return {
            "service_id": service_id,
            "status": "registered",
            "capabilities_added": tool_spec.capabilities
        }
    async def connect_to_data_source(
        self,
        data_source: DataSourceConfig
    ) -> List[str]:
        """Dynamic registration of data-specific tools"""
        schema = await self.analyze_data_schema(data_source)
        generated_tools = []
        # Create CRUD tools for each entity
        for entity in schema.entities:
            crud_tools = self.generate_crud_tools(entity, data_source)
            for tool in crud_tools:
                await self.register_tool(tool, data_source.security_context)
                generated_tools.append(tool.name)
        # Create query tools for relationships
        for relationship in schema.relationships:
            query_tool = self.generate_query_tool(relationship, data_source)
            await self.register_tool(query_tool, data_source.security_context)
            generated_tools.append(query_tool.name)
        return generated_tools

Kubernetes'te, Custom Resource Definition ile dinamik yönetim:

YAML

# Kubernetes CRD for MCP Tool Registration
apiVersion: mcp.dev/v1
kind: MCPTool
metadata:
  name: data-analyzer
  namespace: mcp-tools
spec:
  name: data-analyzer
  version: 2.1.0
  capabilities:
    - text-analysis
    - sentiment-detection
    - entity-extraction
  security:
    authentication:
      type: mTLS
      certSecret: analyzer-cert
    authorization:
      type: RBAC
      roles:
        - mcp-tool-executor
        - data-reader
  endpoint:
    url: https://analyzer.mcp.local
    healthCheck: /health
  schema:
    input:
      type: object
      properties:
        text:
          type: string
          maxLength: 10000
    output:
      type: object
      properties:
        sentiment:
          type: number
        entities:
          type: array
  scaling:
    minReplicas: 2
    maxReplicas: 10
    targetCPU: 70

Güvenlik ve Uyumluluk Değerlendirmeleri

Dinamik kayıt, kendine özgü güvenlik zorlukları doğurur. Kullanıcı A için amaçlanan tool'ların Kullanıcı B'ye açılmasını önlemek için yeni kaydedilen tool'lar session'a özgü olmalıdır; dinamik tool tanımları kullanıcıya özel sunucu bağlamı içinde yaşamalıdır. Sistem, saldırganların modelleri istenmeyen veya zararlı tool'lar kaydeden payload'larla factory tool'ları çağırmaya kandırdığı kötü niyetli kayıt girişimlerine karşı korunmalıdır. Tüm girdiler doğrulanmalıdır; kullanıcı tarafından sağlanan keyfi kod, uygun sandboxing olmadan asla tool olarak kaydedilmemelidir.

Client-Side Cache Stratejisi

Client'lar latency'yi azaltmak için tool listelerini cache'leyebileceğinden, dinamik ortamlarda sağlam bir invalidation stratejisi kritik önemdedir:

Python

import asyncio
from datetime import datetime
class MCPClientCache:
    def __init__(self, cache_backend: CacheBackend, registry_client: RegistryClient):
        self.cache = cache_backend
        self.registry = registry_client
        self.invalidation_subscriptions = {}
    async def get_tool_capabilities(
        self,
        tool_name: str,
        force_refresh: bool = False
    ) -> dict:
        cache_key = f"capabilities:{tool_name}"
        if not force_refresh:
            cached = await self.cache.get(cache_key)
            if cached and not self.is_stale(cached):
                return cached.data
        # Fetch from registry, cache with TTL, and subscribe to changes
        capabilities = await self.registry.get_capabilities(tool_name)
        ttl = self.calculate_ttl(tool_name, capabilities)
        await self.cache.set(cache_key, CacheEntry(data=capabilities, timestamp=datetime.utcnow()), ttl=ttl)
        if tool_name not in self.invalidation_subscriptions:
            await self.subscribe_to_changes(tool_name)
        return capabilities
    async def handle_list_changed(self, notification: dict):
        """Handle MCP list_changed notifications"""
        affected_tools = notification.get("affected_resources", [])
        invalidation_tasks = [self.cache.delete(f"capabilities:{tool}") for tool in affected_tools]
        await asyncio.gather(*invalidation_tasks)
        # Propagate invalidation to dependent caches
        await self.propagate_invalidation(affected_tools)

Tool Pipeability ve Kompozisyon

Tool kompozisyonu, birinin çıktısının diğerinin girdisi olarak kolayca kullanılabileceği tool'lar tasarlamayı, LLM'in bilişsel yükünü azaltan "akan arayüzler" yaratmayı içerir. LLM'ler bağlantıları çıkarsayabilse de bu kırılgan olabilir. Sağlam mimariler, kompozisyonu daha deterministik hale getiren, bir "determinizm gradyanı" boyunca var olan açık pattern'ler kullanır.

Pattern 1: Semantik Tool Açıklaması (Düşük Determinizm) Temel, net iletişimdir: açıklayıcı, eylem odaklı tool adları (örn. generate_report), girdi ve çıktıları belirten dokümantasyon, veri akışı hakkında metinsel ipuçları veren açıklayıcı notasyonlara sahip güçlü tipli schema'lar (örn. "genellikle create_dataset çıktısından gelen, dataset için benzersiz identifier" açıklamalı dataset_id: string).

Pattern 2: Resource Link'ler Üzerinden Açık Pipeability (Orta Determinizm) Tool bağlantılarını veride açık hale getirir. Kaynak üreten tool'lar, çıktılarında resource_link URI'ları içerir. Kaynak tüketen tool'lar, URI kabul eden parametreler tanımlar. LLM'in görevini karmaşık akıl yürütmeden pattern eşleştirmeye indirger.

Pattern 3: Plan Nesnesi Üzerinden Deterministik Kompozisyon (Yüksek Determinizm) Belirsizliği tamamen ortadan kaldıran, en sağlam pattern. Plan Nesnesi, açık çıktı-girdi eşlemesine izin verir (örn. tasks.task_B.parameters.dataset_id = tasks.task_A.outputs.dataset_id). Orkestrasyon, çıkarsama yoluyla değil, spesifikasyon yoluyla sağlanır.

Implementasyon Örneği: Tool Pipeline'ı

Python'da deterministik bir tool pipeline'ı:

Python

from typing import Protocol, TypeVar, Generic, Any
T = TypeVar('T')
U = TypeVar('U')
class PipeableTool(Protocol[T, U]):
    """Protocol for composable tools"""
    def accepts(self) -> type[T]:
        """Input type this tool accepts"""
        ...
    def produces(self) -> type[U]:
        """Output type this tool produces"""
        ...
    async def execute(self, input: T) -> U:
        """Execute tool transformation"""
        ...
class ToolPipeline(Generic[T, U]):
    def __init__(self, initial_tool: PipeableTool[T, Any]):
        self.steps = [initial_tool]
    def pipe(self, tool: PipeableTool) -> 'ToolPipeline':
        """Add tool to pipeline if types match"""
        last_output = self.steps[-1].produces()
        next_input = tool.accepts()
        if not self.types_compatible(last_output, next_input):
            raise TypeError(f"Incompatible pipe: {last_output} -> {next_input}")
        self.steps.append(tool)
        return self
    async def execute(self, input: T) -> Any:
        """Execute complete pipeline"""
        result = input
        for step in self.steps:
            result = await step.execute(result)
        return result
# Usage Example
# pipeline = (
#     ToolPipeline(DataExtractor())
#     .pipe(DataCleaner())
#     .pipe(FeatureGenerator())
#     .pipe(ModelPredictor())
#     .pipe(ResultFormatter())
# )

Kapsamlı Güvenlik, Uyumluluk ve Dağıtım

Güvenlik Implementasyonu Kontrol Listesi

Sağlam güvenlik, defense-in-depth stratejisi gerektirir:

Kimlik Doğrulama ve Yetkilendirme:

  • ✅ Uzak sunucular için PKCE ile OAuth 2.1
  • ✅ Servisten servise iletişim için mTLS
  • ✅ İş yükü kimliği için SPIFFE/SPIRE
  • ✅ Yetenek tabanlı erişim kontrolü

Veri Koruma:

  • ✅ Bekleyen veride AES-256-GCM şifrelemesi
  • ✅ Aktarımda minimum TLS 1.3
  • ✅ Her 30 günde bir key rotasyonu
  • ✅ Hardware Security Module (HSM) entegrasyonu

Uyumluluk Kontrolleri:

  • ✅ Otomatik GDPR silme workflow'ları
  • ✅ CCPA opt-out mekanizmaları
  • ✅ Veri ikameti (data residency) uygulaması
  • ✅ Kapsamlı audit logging

GDPR/CCPA Uyumluluk Matrisi

State yönetimi pattern'i seçiminin doğrudan uyumluluk etkileri vardır:

Pattern GDPR Madde 17 (Silme) CCPA § 1798.105 (Silme) Veri İkameti Audit Kaydı
Server-Side Cache Key silme üzerinden doğrudan implementasyon 45 günlük pencere desteği Redis cluster yerleşimi Eksiksiz audit kaydı
Client Pointer'ları Object storage silme gerektirir Pointer izleme gerektirir CDN coğrafi kısıtlamaları Pointer erişim kayıtları
Stateful Payload'lar Karmaşık (client'ın tuttuğu veri) Kullanıcı bildirimi gerekir Client-side depolama Sınırlı görünürlük

Dağıtım Mimarileri ve Performans

Dağıtım Pattern'leri

Kubernetes Dağıtım Pattern'i

ConfigMap ve StatefulSet içeren tipik bir Kubernetes dağıtımı:

YAML

apiVersion: v1
kind: ConfigMap
metadata:
  name: mcp-server-config
data:
  server.yaml: |
    state_management:
      type: "server_side_cache"
      backend: "redis_cluster"
      compliance:
        gdpr_enabled: true
        ccpa_enabled: true
    orchestration:
      planner_type: "hybrid"
      max_parallel_tasks: 10
    security:
      authentication: "oauth2"
      authorization: "rbac"
      mtls_required: true
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mcp-server
spec:
  serviceName: mcp-server
  replicas: 3
  template:
    spec:
      containers:
      - name: mcp-server
        image: mcp-server:latest
        env:
        - name: STATE_STORE
          value: "redis://redis-cluster:6379"
        - name: ENABLE_MTLS
          value: "true"
        volumeMounts:
        - name: config
          mountPath: /config
        - name: certs
          mountPath: /certs
      volumes:
      - name: config
        configMap:
          name: mcp-server-config
      - name: certs
        secret:
          secretName: mcp-server-certs
Serverless Dağıtım (AWS Lambda)

AWS Lambda ve DynamoDB kullanan serverless mimari:

Python

# SAM template for serverless MCP
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Resources:
  MCPPlannerFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: planner/
      Handler: app.lambda_handler
      Runtime: python3.11
      Timeout: 30
      MemorySize: 1024
      Environment:
        Variables:
          STATE_TABLE: !Ref StateTable
          TOOL_REGISTRY: !Ref ToolRegistry
      Events:
        MCPApi:
          Type: HttpApi
          Properties:
            Path: /mcp/plan
            Method: POST
            Auth:
              Authorizer: OAuth2
  StateTable:
    Type: AWS::DynamoDB::Table
    Properties:
      BillingMode: PAY_PER_REQUEST
      StreamSpecification:
        StreamViewType: NEW_AND_OLD_IMAGES
      TimeToLiveSpecification:
        Enabled: true
        AttributeName: ttl

Performans Kıyaslamaları

State Yönetimi Performansı
Pattern Latency (p99) Throughput Bellek/Session Maliyet/Milyon İşlem
Server-Side Cache 5ms 100K işlem/s 2KB 0,08 $
Client Pointer'ları 15ms 50K işlem/s 200B 0,12 $
Stateful Payload'lar 1ms 200K işlem/s 0 0,02 $
Orkestrasyon Performansı
Pattern Planlama Süresi Çalıştırma Ek Yükü Başarı Oranı Token Maliyeti
Proaktif 8-12sn Düşük (%5) %85 5.000
Reaktif 2-3sn/adım Yüksek (%25) %70 500 × N
Hibrit 4-5sn Orta (%10) %92 3.000 + adaptif

Sonuç ve Öneriler

Mimari Pattern'lerin Özeti

Bu analiz, gelişmiş MCP sunucuları için üç kritik mimari alanı ele aldı: karmaşık çok turlu workflow'ları yönetmek için state yönetimi modelleri, güvenilir görev çalıştırma için planner tool orkestrasyonu ve uyarlanabilir, kompoze edilebilir sistemler kurmak için dinamik yetenek pattern'leri. Mimarlar bu pattern'leri uygulayarak, güvenlik, uyumluluk ve performans açısından kurumsal gereksinimleri karşılayan, production'a hazır MCP sunucuları inşa edebilir ve AI-first sistemlerin geleneksel yazılım servisleri kadar ölçeklenebilir ve güvenilir olmasının önünü açabilirler.

Temel Öneriler

  1. State Yönetimi Stratejisi: Önerilen evrimsel yol, maksimum güvenlik ve uyumluluğu garanti eden server-side caching ile başlar, ardından uygulamalar daha büyük hacimleri karşılayacak ve bellek ayak izini azaltacak şekilde ölçeklendikçe client-side pointer'lara geçer.
  2. Orkestrasyon Stratejisi: Güvenilirlik, verimlilik ve uyarlanabilirlik arasında en iyi dengeyi kurmak için, proaktif planlamanın önceden sağladığı kontrolü, beklenmedik sonuçlar için reaktif uyarlamanın esnekliğiyle birleştiren bir hibrit planner uygulayın.
  3. Dinamik Yetenekler Stratejisi: Tool yaşam döngüsü yönetimi için Kubernetes operator'ları veya benzeri deklaratif mekanizmalar kullanarak sağlam, ölçeklenebilir dinamik tool yönetimi sağlayın. Etkileşimleri, SPIFFE/SPIRE gibi modern iş yükü kimliği standartlarına sahip bir service mesh ile güvence altına alın.

Implementasyon Öncelikleri ve Başarı Metrikleri

Aşamalı bir implementasyon yol haritası, karmaşıklığı yönetirken artımlı değer sunulmasına olanak tanır:

  1. Temel katman olarak, tam GDPR/CCPA uyumluluğuna sahip güvenli state yönetimini kurun
  2. Sağlam DAG çalıştırması ile temel bir planner tool dağıtın
  3. Tüm tool endpoint'leri için zorunlu mTLS ile güvence altına alınmış dinamik tool kaydını uygulayın
  4. Tool pipeability, client-side caching ve sofistike hata yönetimi gibi ileri özellikleri kademeli olarak ekleyin

Başarı, net, ölçülebilir metriklere karşı değerlendirilir:

  • State işlemi latency'si: < 10ms (p99)
  • Planlama güvenilirliği: > %90 görev başarı oranı
  • Tool kayıt süresi: < 1 saniye
  • GDPR uyumluluğu: 30 günlük gereksinim içinde %100 silme yerine getirme
  • Güvenlik: Sıfır yetkisiz tool çalıştırması

Bu pattern'ler, yalnızca işlevsel MCP sunucuları için değil, yeni nesil AI destekli uygulamalar için sağlam, güvenli ve ölçeklenebilir altyapı inşa etmenin de temelini oluşturuyor. Kurumsal AI'ın geleceği, akıcı, konuşma temelli LLM'ler ile yapılandırılmış, güvenli kurumsal sistemler arasındaki boşluğu kapatan mimarilere bağlı. Bu pattern'lerle ekipler, tam da bu köprüyü kurmaya hazır hale geliyor: gerçek production ortamlarının karmaşıklıklarını, ölçek gereksinimlerini ve uyumluluk taleplerini karşılayabilecek bir köprü.

İlgili hizmet

AI fikrinin yatırıma değip değmeyeceğine bakın

AI danışmanlığında kullanım senaryosunu, eldeki kanıtı, gereken kontrolleri ve işin kimde olacağını birlikte değerlendiriyoruz.
AI danışmanlığını inceleyin

İletişim

Verilerinizi nasıl işliyoruz

Tam sayfada aç