---
title: 'Sunucu Yetenekleri'
source: 'https://academia.sh/tr/kurslar/mcp/sunucu-yetenekleri'
course: 'Model Bağlam Protokolü ve Araç Ekosistemi'
language: tr
updated: '2026-08-17T18:06:40+00:00'
license: 'CC BY-SA 4.0'
---

# Sunucu Yetenekleri

Bildirilen yetenek ile anlaşılan yetenek arasındaki farkın sayılması: üç kurgu sunucu 5 araç, 2 kaynak ve 1 istem bildiriyor, istemcinin izin listesi 4 araç taşıyor ve el sıkışmasından yalnız 3 araç çıkıyor. İki koşum aynı bedeli ödüyor — 3 istek, 3 yanıt, 99 belirteç, 5 gidiş-dönüş ve 0 hata — ama sonuçları ayrışıyor: sürümler hizalıyken 4 araç anlaşılıyor ve izin listesi kayit_yaz aracını kasten düşürüyor, sürüm sapmalıyken kayit sunucusunun tamamı düşüyor ve izin listesinde bulunan bolge_ozet aracı hiçbir hata üretmeden kayboluyor. Bir sunucunun düşmesi araçlarıyla birlikte kaynak ve istem bildirimlerini de götürüyor; olcum düşerse anlaşılan araç 2'ye iniyor. İki kayıp aynı hata metnini veriyor, biri kasıt biri kazadır.

Önceki derste veri katmanının üç mesaj türü sayıldı: istek, yanıt ve bildirim. Sekiz abonelik toplu
iş 48 mesaja bölündü, 640 belirteç etti ve bunun 384'ü yalnız zarftı. Ama o mesajların hepsi
**anlaşılmış** bir araç kümesi üzerinde çalıştı ve o kümenin nasıl oluştuğu sorulmadı.

Bu ders o kümeyi kurar. Bir sunucu bağlandığında ne yapabildiğini kendisi bildirir; bu bildirim üç
kalem taşır: **araç**, **kaynak (resource)** ve **istem**. İstemci bildirilenin tamamını almaz.
Ölçülecek olan **bildirilen ile anlaşılan arasındaki farktır** ve bu farkın kaç mesajda, hangi
hatayla oluştuğudur. Ders bir de ters yönde okunur: protokolsüz kurulumda beş aracın hepsi elin
altındaydı; protokol bu kümeyi **daraltıyor** ve daraltmanın bir kısmı kasıt, bir kısmı kazadır.

- **PY38.** Ortam, üç sunucu, araçlar ve zarf sayımı **kurgudur**; gerçek bir sunucu, istemci
  kitaplığı ya da çalışma zamanı çağrılmaz. Tohum **20260218**. El sıkışmasında rastgelelik
  yoktur: bu dersin bütün sayıları **koşumdan bağımsızdır** ve iki koşum, aynı sunucu kümesine
  bağlanan **iki istemci yapılandırmasıdır**.
- **PY39.** **Yetenek bildirimi (capability declaration)** üç kalem taşır: çağrılabilir **araç**,
  okunabilir **kaynak** ve hazır **istem**. Bu kursta yalnız araç çağrılır; kaynak ile istem
  **bildirim olarak sayılır** ve erişim hattı kurulmaz.
- **PY40.** **Yetenek uzlaşması (capability negotiation)** el sıkışmasında geçer: istemci her
  sunucuya yetenek sorar, sunucu bildirir, istemci iki süzgeçten geçirir.
- **PY41.** Birinci süzgeç **sürüm sapmasıdır (version skew)**: istemcinin bildiği sürüm sunucunun
  sürümünden küçükse **o sunucunun tamamı** düşer.
- **PY42.** İkinci süzgeç **izin listesidir**: listede olmayan araç, sunucusu geçse bile alınmaz.
- **PY43.** İki süzgeç de el sıkışmasının **yanıtından sonra** çalışır; bedel ödendikten sonra
  daralma olur ve daralma **hata üretmez**.
- **PY44.** **Protokolsüz taban** budur: beş aracın beşi de ders içinde tanımlıdır, el sıkışması
  yoktur, hiçbir araç düşmez.
- **PY45.** Küme küçüktür: üç sunucu, beş bildirilen araç, dört izinli araç. Bu kümede bir oranın
  en küçük adımı **1/5 = 0,2000**'dir; bundan küçük fark **ölçülemez**, bu yüzden oran yerine
  **sayım** basılır.
- **PY46.** Yetenek uzlaşması iki yönlüdür ve istemci de kendi yeteneklerini bildirir. Bu kurgu
  yalnız **sunucu tarafını** modeller, çünkü ölçülen şey sunucunun bildirdiğinin ne kadarının
  alındığıdır.

## Sunucunun Bildirdiği

Bir sunucunun bildirimi bir araç listesinden ibaret değildir. Üç kalem taşır ve üçü de aynı yanıtın
içinde gelir. **Araç** çağrılabilir bir işlevdir; bir adı, alanları ve yan etki bilgisi vardır.
**Kaynak** okunabilir bir içeriktir; sunucunun istemciye açtığı bir belge, tablo ya da listedir.
**İstem** hazır bir istem şablonudur; sunucu kendi alanını bilen bir metni istemciye verir. Gömme
Vektörleri ve Erişim Artırılmış Üretim kursunda erişim hattının kendisi ölçülmüştü; burada o hat
kurulmaz. Kaynak ile istem bu derste **birer bildirim kalemi** olarak sayılır, çünkü sunucu
düştüğünde onlar da düşer ve bu düşüş araçla aynı sessizlikte olur.

```python
TOHUM, M32 = 20260218, 0xFFFFFFFF


def uretec(t):
    x = ((t ^ (t >> 16)) * 2246822507) & M32
    x = ((x ^ (x >> 13)) * 3266489909) & M32
    s = [(x ^ (x >> 16)) & M32]

    def sonraki():
        s[0] = (s[0] * 1664525 + 1013904223) & M32
        return s[0] / 4294967296
    return sonraki


def belirtecle(m):
    b = []
    for s in str(m).lower().replace(",", " , ").split():
        while len(s) > 5:
            b.append(s[:5])
            s = s[5:]
        b.append(s)
    return b


# ---- KURGU ortam ve araclar (M28/K05 ile ayni kurgu, burada sunucuya tasiniyor)
BOLGE = ["dogu", "bati", "kuzey", "guney", "merkez"]
TIP = ["mesken", "isyeri"]
ABONE = {}
for i in range(60):
    r = uretec(TOHUM + 31 * i)
    onceki = 10000 + int(r() * 80000)
    ABONE[f"A{i + 1:03d}"] = {"bolge": BOLGE[int(r() * 5)], "tip": TIP[int(r() * 2)],
                              "onceki": onceki, "simdiki": onceki + int(r() * 70)}
BASAMAK, USTU, ISYERI_KAT = ((10, 4), (25, 7), (40, 11)), 16, 2


def _bedel(m3, tip):
    kalan, alt, top = m3, 0, 0
    for ust, birim in BASAMAK:
        dilim = min(kalan, ust - alt)
        if dilim <= 0:
            break
        top += dilim * birim
        kalan -= dilim
        alt = ust
    return (top + kalan * USTU) * (ISYERI_KAT if tip == "isyeri" else 1)


def t_sayac(abone=None, **_):
    a = ABONE.get(abone)
    return {"hata": "abone yok"} if a is None else {
        "onceki": a["onceki"], "simdiki": a["simdiki"], "tip": a["tip"]}


def t_tuketim(onceki=None, simdiki=None, **_):
    if onceki is None or simdiki is None:
        return {"hata": "eksik alan"}
    f = simdiki - onceki
    return {"m3": f + 100000 if f < 0 else f}


def t_tarife(m3=None, tip="mesken", **_):
    return {"hata": "eksik alan"} if m3 is None else {"tutar": _bedel(m3, tip)}


def t_bolge(bolge=None, **_):
    if bolge not in BOLGE:
        return {"hata": "bolge yok"}
    n = sum(1 for a in ABONE.values() if a["bolge"] == bolge)
    return {"bolge": bolge, "abone": n}


def t_kayit(abone=None, sutun=None, deger=None, **_):
    if not (abone and sutun and deger is not None):
        return {"hata": "eksik alan"}
    return {"yazildi": True}


# ---- KURGU sunucular: her biri yetenek bildirir
SUNUCU = {
    "olcum": {"surum": 2, "aktarim": "yerel",
              "arac": {"sayac_oku": {"islev": t_sayac, "alan": ("abone",), "yan_etki": False},
                       "tuketim": {"islev": t_tuketim, "alan": ("onceki", "simdiki"),
                                   "yan_etki": False}},
              "kaynak": ("abone_listesi",), "istem": ()},
    "tarife": {"surum": 1, "aktarim": "uzak",
               "arac": {"tarife": {"islev": t_tarife, "alan": ("m3", "tip"), "yan_etki": False}},
               "kaynak": ("basamak_tablosu",), "istem": ("bedel_aciklamasi",)},
    "kayit": {"surum": 3, "aktarim": "uzak",
              "arac": {"bolge_ozet": {"islev": t_bolge, "alan": ("bolge",), "yan_etki": False},
                       "kayit_yaz": {"islev": t_kayit, "alan": ("abone", "sutun", "deger"),
                                     "yan_etki": True}},
              "kaynak": (), "istem": ()},
}
ISTEMCI_SURUM = {"olcum": 2, "tarife": 1, "kayit": 2}      # kayit sunucusu ileride
IZIN = ("sayac_oku", "tuketim", "tarife", "bolge_ozet")     # kayit_yaz izin listesinde yok

SAYIM = {"istek": 0, "yanit": 0, "bildirim": 0, "belirtec": 0, "gidis_donus": 0}


def mesaj(tur, govde, aktarim="yerel"):
    """KURGU zarf. Gercek bir protokol uygulanmaz; sayilan sey zarfin bedelidir."""
    SAYIM[tur] += 1
    b = len(belirtecle(govde)) + 8                       # zarf sabiti
    SAYIM["belirtec"] += b
    if tur == "istek":
        SAYIM["gidis_donus"] += 2 if aktarim == "uzak" else 1
    return b


def elsikismasi(istemci_surum=None, izin=None):
    """Yetenek uzlasmasi: surum uyusmazligi ve izin listesi arac kumesini daraltir."""
    istemci_surum = ISTEMCI_SURUM if istemci_surum is None else istemci_surum
    izin = IZIN if izin is None else izin
    anlasilan, dusen = {}, []
    for ad, s in SUNUCU.items():
        mesaj("istek", f"yetenek sor {ad}", s["aktarim"])
        mesaj("yanit", f"yetenek bildir {ad} surum {s['surum']} "
                       + " ".join(s["arac"]) + " " + " ".join(s["kaynak"]))
        if istemci_surum.get(ad, 0) < s["surum"]:
            dusen.append((ad, "surum", s["surum"], istemci_surum.get(ad, 0)))
            continue
        for t, tan in s["arac"].items():
            if t not in izin:
                dusen.append((ad, "izin", t, None))
                continue
            anlasilan[t] = dict(tan, sunucu=ad, aktarim=s["aktarim"])
    return anlasilan, dusen


def cagir(anlasilan, ad, durum):
    if ad not in anlasilan:
        return {"hata": "arac bildirilmedi"}
    t = anlasilan[ad]
    kw = {a: durum[a] for a in t["alan"] if a in durum}
    mesaj("istek", f"{ad} " + " ".join(f"{k} {v}" for k, v in kw.items()), t["aktarim"])
    s = t["islev"](**kw)
    mesaj("yanit", " ".join(f"{k} {v}" for k, v in s.items()))
    return s


print("sunucu  surum aktarim  arac  kaynak  istem")
for ad, s in SUNUCU.items():
    print(f"{ad:<7} {s['surum']:>5} {s['aktarim']:<8} {len(s['arac']):>5}"
          f" {len(s['kaynak']):>7} {len(s['istem']):>6}")
print(f"bildirilen: {sum(len(s['arac']) for s in SUNUCU.values())} arac,"
      f" {sum(len(s['kaynak']) for s in SUNUCU.values())} kaynak,"
      f" {sum(len(s['istem']) for s in SUNUCU.values())} istem;"
      f" izin listesi {len(IZIN)} arac")
```

```
sunucu  surum aktarim  arac  kaynak  istem
olcum       2 yerel        2       1      0
tarife      1 uzak         1       1      1
kayit       3 uzak         2       0      0
bildirilen: 5 arac, 2 kaynak, 1 istem; izin listesi 4 arac
```

Protokolsüz taban bu tablonun tamamıdır: araçlar ders içinde tanımlı olsaydı beşinin de elin
altında olurdu. İzin listesi dördünü onaylıyor. Aradaki tek araç `kayit_yaz`, tek yan etkili
araçtır ve dışarıda bırakılması bir karardır — Yapay Zekâ Ajanları kursunda aynı liste 20 çağrıyı
durdurmuştu ve o yordam burada tekrarlanmaz.

## Bildirilen ile Anlaşılan

El sıkışması her sunucuya bir istek gönderir, bir yetenek yanıtı alır ve iki süzgeci **yanıttan
sonra** çalıştırır. Aşağıdaki iki koşumda tek fark istemcinin `kayit` sunucusu için bildiği
sürümdür. Web API Tasarımı kursunda sürümleme ve geriye uyum yordamı ölçülmüştü; burada
tekrarlanmaz, yalnız sapmanın araç kümesine ne yaptığı sayılır.

```python
def sifirla():
    for k in SAYIM:
        SAYIM[k] = 0


HIZALI = {"olcum": 2, "tarife": 1, "kayit": 3}     # istemci ucuncu sunucunun surumunu de biliyor

for etiket, sur in (("hizali", HIZALI), ("sapmali", ISTEMCI_SURUM)):
    sifirla()
    anlasilan, dusen = elsikismasi(sur)
    print(f"istemci kayit sunucusunu surum {sur['kayit']} biliyor  ({etiket})")
    print(f"  el sikismasi : {SAYIM['istek']} istek, {SAYIM['yanit']} yanit,"
          f" {SAYIM['belirtec']} belirtec, {SAYIM['gidis_donus']} gidis-donus, 0 hata")
    print(f"  anlasilan {len(anlasilan)} : {' '.join(sorted(anlasilan))}")
    for s_ad, tur, a, b in dusen:
        neden = f"arac {a} izin listesinde yok" if tur == "izin" else \
            f"sunucu surum {a}, istemci surum {b}"
        print(f"  dusen        : {s_ad} sunucusu, {neden}")
```

```
istemci kayit sunucusunu surum 3 biliyor  (hizali)
  el sikismasi : 3 istek, 3 yanit, 99 belirtec, 5 gidis-donus, 0 hata
  anlasilan 4 : bolge_ozet sayac_oku tarife tuketim
  dusen        : kayit sunucusu, arac kayit_yaz izin listesinde yok
istemci kayit sunucusunu surum 2 biliyor  (sapmali)
  el sikismasi : 3 istek, 3 yanit, 99 belirtec, 5 gidis-donus, 0 hata
  anlasilan 3 : sayac_oku tarife tuketim
  dusen        : kayit sunucusu, sunucu surum 3, istemci surum 2
```

İki koşumun **bedeli birebir aynıdır**: 3 istek, 3 yanıt, 99 belirteç, 5 gidiş-dönüş ve iki
koşumda da **sıfır hata**. Sonuçları ayrışıyor. Sürümler hizalıyken anlaşılan araç **dört**,
sapmalıyken **üç**. Kaybolan araç `bolge_ozet`, ve o araç **izin listesindedir** — istemci onu
kullanmayı açıkça onaylamıştır. Sunucusunun sürümü uymadığı için alınmadı.

İki düşüş satırı aynı kümede duruyor ama aynı şey değiller. `kayit_yaz` düşüşü **kasıttır**: yan
etkili araç izin listesine konmadı ve protokol bu kararı uyguladı. `bolge_ozet` düşüşü
**kazadır**: kimse bu aracı dışarıda bırakmaya karar vermedi, istemcinin bildiği sürüm numarası
eskiydi. İkisi de aynı sessizlikte oldu; el sıkışması ikisi için de sıfır hata bildirdi. Kursun
ikinci iddiasının ikinci örneği budur: **standartlaştırmak da bozar**. Protokolsüz kurulumda beş
araç elin altındaydı, protokollü kurulumda üç kaldı ve düşen ikisinden biri istenmeyen bir kayıptır.

## Sunucu Düştüğünde Ne Gider

Sapma bir aracı değil bir **sunucuyu** düşürüyor. Bunun ölçüsü, her sunucunun sürümü bir eksik
bilindiğinde nelerin gittiğidir. Aynı çağrı iki yapılandırmada da denenir; hata metni aynıdır.

```python
print("dusen sunucu  kaybolan arac  kaynak  istem   kalan anlasilan arac")
for ad, s in SUNUCU.items():
    anlasilan, _ = elsikismasi(dict(HIZALI, **{ad: s["surum"] - 1}))
    print(f"{ad:<13} {len(s['arac']):>13} {len(s['kaynak']):>7} {len(s['istem']):>6}"
          f" {len(anlasilan):>22}")

print("\nayni hata metni, iki ayri neden:")
for etiket, sur in (("hizali ", HIZALI), ("sapmali", ISTEMCI_SURUM)):
    anlasilan, _ = elsikismasi(sur)
    print(f"  {etiket}  bolge_ozet -> {cagir(anlasilan, 'bolge_ozet', {'bolge': 'dogu'})}")
    print(f"  {etiket}  kayit_yaz  -> "
          f"{cagir(anlasilan, 'kayit_yaz', {'abone': 'A017', 'sutun': 'bedel', 'deger': 844})}")
```

```
dusen sunucu  kaybolan arac  kaynak  istem   kalan anlasilan arac
olcum                     2       1      0                      2
tarife                    1       1      1                      3
kayit                     2       0      0                      3

ayni hata metni, iki ayri neden:
  hizali   bolge_ozet -> {'bolge': 'dogu', 'abone': 11}
  hizali   kayit_yaz  -> {'hata': 'arac bildirilmedi'}
  sapmali  bolge_ozet -> {'hata': 'arac bildirilmedi'}
  sapmali  kayit_yaz  -> {'hata': 'arac bildirilmedi'}
```

Tablo düşüşün birimini gösteriyor. Bir sunucunun sürümü uymadığında yalnız bir araç değil, o
sunucunun **bütün bildirimi** gider: `olcum` düşerse iki araç ve bir kaynak, `tarife` düşerse bir
araç, bir kaynak ve bir istem. Kaynak ile istem bu kursta çağrılmıyor, ama sayıda duruyorlar çünkü
kaybolan yetenek yalnız çağrılabilir olan değildir. En sert satır ilk satırdır: `olcum` yerel
aktarımda çalışan ve en çok kullanılan sunucudur, düştüğünde anlaşılan araç dörtten **ikiye** iner.

Son dört satır sessizliğin nasıl göründüğünü veriyor. Sürümler hizalıyken `bolge_ozet` çağrısı
doğu bölgesinde **11 abone** döndürüyor. Sapmalı yapılandırmada aynı çağrı, aynı kod ve aynı istemle
`{'hata': 'arac bildirilmedi'}` veriyor — `kayit_yaz` çağrısının verdiği metnin aynısı. Kasıtlı
düşüş ile kazayla düşüş çağrı anında **ayırt edilemez**; ayırt eden tek şey el sıkışmasının düşen
listesidir, ve o liste ancak sayılırsa görünür.

Sayının biçimi de bir karardır. Anlaşılan üç araç bildirilen beşin 0,6000'idir, ama bu kümede bir
oranın en küçük adımı **1/5 = 0,2000**'dir: tek bir aracın gidip gelmesi oranı iki yüz birimlik
adımlarla oynatır ve bundan küçük hiçbir fark ölçülemez. Bu yüzden bu derste oran değil **sayım**
basılır — beş bildirilen, dört izinli, üç anlaşılan, bir kasıtlı düşüş, bir kazara düşüş.

Bu sayımın kime düştüğü de bir karardır. Sunucu bildirdiğini bilir, istemci aldığını bilir; ikisini
yan yana koyan bir taraf yoksa fark hiçbir yerde durmaz. Kursun kuralı burada okunur: bir araç
bağlantısının sayısı aracın sayısı değil **sözleşmenin sayısıdır** ve değiştiğinde kimin
kırılacağı yazılmayan arayüz ölçülmemiş sayılır. Bu derste kırılan taraf istemcidir, kıran şey
sunucunun sürüm numarasıdır ve arada hiçbir hata mesajı yoktur. İstemcinin elindeki tek çare el
sıkışmasının iki ucunu saymaktır: kaç araç bildirildi, kaçı anlaşıldı, düşenlerin hangisi izin
kararı hangisi sürüm sapması.

## Özet

- Bir yetenek bildirimi üç kalem taşır: çağrılabilir araç, okunabilir kaynak ve hazır istem; üçü de
  aynı yanıtta gelir ve sunucu düştüğünde üçü birden gider.
- Üç kurgu sunucu 5 araç, 2 kaynak ve 1 istem bildiriyor; izin listesi 4 aracı onaylıyor ve el
  sıkışmasından 3 araç çıkıyor.
- İki yapılandırma aynı bedeli ödüyor — 3 istek, 3 yanıt, 99 belirteç, 5 gidiş-dönüş ve 0 hata —
  ama sürümler hizalıyken 4, sapmalıyken 3 araç anlaşılıyor.
- Sürüm sapması bir aracı değil bir sunucuyu düşürür: izin listesinde bulunan `bolge_ozet` hiçbir
  hata üretmeden kayboluyor; `olcum` düşseydi anlaşılan araç 2'ye inerdi.
- Düşen iki araçtan biri kasıt biri kazadır ve çağrı anında ikisi de aynı hata metnini verir;
  ayrımı yalnız el sıkışmasının düşen listesi gösterir.
- Beş araçlık kümede bir oranın en küçük adımı 0,2000'dir; bu yüzden oran değil sayım basılır.

## Sonraki Adım

Beş derste model bağlam protokolü **dışarıdan** anlatıldı. Standartlaşmanın ne kazandırdığı, üç
rolün sorumlulukları, aktarım katmanının gidiş-dönüş farkı, veri katmanının üç mesaj türü ve
sunucunun bildirdiği yetenekler ölçüldü; her ölçünün yanına protokolsüz taban ile bedeli yazıldı.
Ama bütün bu sayılar hazır kurulmuş bir kurgunun üzerinde okundu: **hiçbir sunucu ve hiçbir istemci
yazılmadı.** Bir sunucunun yeteneğini gerçekten bildirmesi için hangi işleyicilerin yazılması
gerektiği, bir istemcinin sunucuyu nasıl keşfedip oturum açtığı ve bu derste sayılan sessiz düşüşün
istemci kodunda **hangi satırda** oluştuğu hiç sorulmadı. Sonraki konu protokolü kurmaktan
gerçekleştirmeye geçer ve önce sunucu tarafını yazar.
