SSD Nodes Learn Hosting plans →
Rehberler Matt ConnorYazan Matt Connor

VPS üzerinde MCP sunucusu nasıl kurulur?

Claude Code ve AI ajanları için VPS üzerinde stdio ve HTTP tabanlı MCP sunucularını yapılandırın. systemd, TLS ve güvenli kimlik doğrulama ile araç erişimini yönetin.

Ne inşa ediyorsunuz

Tek bir VPS üzerinde iki adet çalışan MCP kurulumu. Birincisi, Claude Code tarafından bir alt süreç olarak başlatılan ve bir pipe üzerinden iletişim kuran, dosya sistemi veya veritabanı aracı olan bir stdio sunucusu. İkincisi ise systemd ve TLS destekli bir nginx reverse proxy arkasında uzun ömürlü bir ağ servisi olarak çalışan, işaret ettiğiniz herhangi bir MCP istemcisi tarafından erişilebilen uzak HTTP sunucusu. Her ikisinin kurulumu da oldukça küçüktür. Bu kılavuzun büyük bir kısmı, aslında sorun çıkaran iki konuya odaklanmaktadır: JSON-RPC akışını temiz tutmak ve kimlik doğrulaması yapılmamış bir araç uç noktasını asla genel internete açmamak.

MCP'nin gerçekte ne olduğu

Model Context Protocol; bir yapay zeka istemcisinin (Claude Code, Claude Desktop, VPS üzerinde Gemini CLI veya kendi yazdığınız bir betik), harici araçları çağırması ve harici kaynakları okuması için kullanılan standart bir yöntemdir. Modelin kendisi herhangi bir işlem çalıştırmaz. İstemciye talepte bulunur, istemci bir MCP sunucusu ile JSON-RPC 2.0 üzerinden haberleşir, sunucu aracı çalıştırır ve sonucu geri iletir. İnsanların agent harness dediklerinde kastettikleri şey bu istemcidir: modelin etrafındaki, araç listesini, izin denetimlerini ve oturum durumunu yöneten döngü; MCP ise bu yapının araç tarafını genişletmenizi sağlayan basit bir protokoldür. Tek bir protokol sayesinde, bir kez yazdığınız sunucu, MCP destekleyen tüm istemcilerle çalışır. Eğer bu ayrım sizin için yeniyse ve özellikle modelin bir araca başvurmaya nasıl karar verdiği konusu ilginizi çekiyorsa, bu sunuculardan birine gerçek kimlik bilgileri vermeden önce agent temellerine dair aşamalı bir yol haritası üzerinde bir saat vakit ayırmanız faydalı olacaktır.

İki tür taşıma yöntemi mevcuttur ve bu kılavuzun geri kalanı bu iki yöntem etrafında şekillenir:

  • stdio. İstemci, sunucuyu bir alt süreç (child process) olarak başlatır ve standart girdi/çıktı (stdin/stdout) üzerinden satır sonu karakteriyle ayrılmış JSON-RPC mesajları alışverişi yapar. Ağ bağlantısı, port veya kimlik doğrulama yoktur; güven sınırı sürecin kendisidir. Neredeyse tüm yerel araçlar bu şekilde çalışır.
  • Streamable HTTP (ve onun eski sürümü olan HTTP+SSE). Sunucu, sürekli çalışan bir web servisidir. İstemci HTTP üzerinden bağlanır ve sunucu, yanıtları Server-Sent Events (SSE) aracılığıyla akış olarak gönderebilir. Bir sunucuyu birden fazla istemciyle paylaşmak veya kalıcı olarak sunucuda çalışması gereken bir araç çalıştırmak istediğinizde bu yöntem kullanılır.

Araç tek bir makineye ve tek bir kullanıcıya aitse stdio yöntemini seçin. Paylaşılan bir servis ise HTTP yöntemini tercih edin.

Ön gereksinimler ve dikkat edilmesi gereken noktalar

root veya sudo yetkilerine sahip, temiz bir Ubuntu 24.04 KVM VPS kullandığınızı varsayıyoruz. Bunların dışında şunlar gereklidir:

  • Sunucunun yazıldığı çalışma zamanı. Çoğu referans sunucu Node veya Python ile yazılmıştır. Ubuntu 24.04, Node 18 sürümüyle gelir; ancak güncel birçok MCP paketi Node 20 veya daha yeni bir sürüm gerektirir. Bu nedenle apt paketine güvenmek yerine NodeSource veya nvm üzerinden güncel bir LTS sürümü kurun. Python 3.12 halihazırda yüklüdür.
  • Bir alan adı ve DNS A kaydı. Bu sadece uzak HTTP sunucusu için gereklidir; TLS, bu VPS'e yönlenen bir alan adına ihtiyaç duyar. stdio örneği için herhangi bir DNS kaydına gerek yoktur.
  • 512 MB RAM fazlasıyla yeterlidir. MCP sunucuları hafif JSON-RPC süreçleridir; bellek kullanımı protokolün kendisinden değil, aracınızın etkileşime girdiği bileşenlerden (veritabanı sürücüsü, dosya önbelleği vb.) kaynaklanır.
  • Spesifikasyon henüz yeni ve gelişmektedir. 2025-03-26 tarihli revizyon, HTTP+SSE yapısını Streamable HTTP ile değiştirmiş ve SSE'yi kullanımdan kaldırmıştır. SSE hala çalışmaktadır ve birçok sunucu bu yapıyı desteklemeye devam etmektedir; bu nedenle herhangi bir taşıma protokolü kısıtlamasını mutlak bir kural olarak değil, sunucunun sürüm notlarına göre tekrar kontrol edilmesi gereken bir yapılandırma olarak değerlendirin.

Adım 1: Bir stdio sunucusunu Claude Code'a bağlama

Dosya sistemi sunucusuyla başlayın; bu sunucu resmi, aktif olarak bakımı yapılan ve Node dışında hiçbir şeye ihtiyaç duymayan bir araçtır. Aşağıdaki tek komut, sunucuyu Claude Code'a kaydeder ve mevcut proje ile sınırlandırarak commit edilebilir bir dosyaya yazılmasını sağlar:

cd /home/matt/projects/api
claude mcp add --scope project --transport stdio filesystem \
  -- npx -y @modelcontextprotocol/server-filesystem /home/matt/projects/api

-- ayırıcısı önemlidir: ondan sonra gelen her şey Claude Code'un çalıştıracağı komuttur, Claude Code'a ait bir flag değildir. Bu işlem proje kök dizinine bir .mcp.json yazar:

{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-filesystem",
        "/home/matt/projects/api"
      ]
    }
  }
}

Henüz hiçbir şey çalışmıyor. Bu dizinde bir sonraki sefer Claude Code'u başlattığınızda, ajan .mcp.json dosyasını okur, npx -y @modelcontextprotocol/server-filesystem ... sürecini bir alt süreç olarak başlatır ve bu sürecin stdin/stdout kanalları üzerinden MCP el sıkışmasını gerçekleştirir. Bağlantının kurulduğunu doğrulayın:

claude mcp list

Sağlıklı bir sunucu, komutunu ve yeşil bir onay işaretini (filesystem: npx -y @modelcontextprotocol/server-filesystem ... - ✔ Connected) yazdırır. Oturum içerisinde /mcp eğik çizgi komutu, sunucunun sunduğu araçları (read_text_file, write_file, list_directory) listeler ve ajan artık bu araçları izin verdiğiniz yollar üzerinde çağırabilir. Bir veritabanı aracı da aynı yapıdadır; paketi değiştirin ve son argüman olarak bir bağlantı dizgisi (connection string) geçin. Ancak, referans Postgres sunucusu birden fazla kez el değiştirdiği için güncel paket adı konusunda sunucunun kendi deposunu kontrol edin.

Ajanı sunucu üzerinde çalıştırmanın temel amacı budur: Claude Code oturumu VPS üzerinde tmux içinde yaşar ve stdio sunucuları, proje dosyalarına ve yerel servislere doğrudan erişim sağlayarak hemen yanında çalışır; böylece ağ üzerinden gidiş-dönüş süresi oluşmaz. Ajan write_file ve read_text_file yeteneklerine sahip olduğunda, bu erişim gücünü çalışan en küçük değişikliğe odaklanma becerisi ile birleştirmek faydalıdır; çünkü bir dosya sistemi aracı, kapsamlı bir yeniden yazımı iki satırlık bir düzeltme kadar kolay hale getirir. Aynı bağlantı mantığı yerel dosyaların ötesine de uzanır: Eğer VPS üzerinde halihazırda bir arama motoru çalıştırıyorsanız, kendi SearXNG örneğinizi ajana bir arama aracı olarak verebilirsiniz. Bu, sorguları kendi sunucunuzda tutar ancak güvenilmeyen sayfa metinlerini doğrudan ajanın üzerinde işlem yapacağı bağlama çeker.

Adım 2: Uzak bir HTTP sunucusu oluşturma

Bir stdio sunucusu, üst süreciyle birlikte sonlanır ve her istemci için bir kez başlatılır. Bu nedenle, birbirine iş devreden iki Claude Code oturumunu aynı makinede çalıştırırsanız, her biri aracın kendi özel kopyasına sahip olur. Her istemci için sürekli çalışan, paylaşımlı bir operasyon aracı, veritabanı ağ geçidi veya hem dizüstü bilgisayarınızın hem de CI sisteminizin çağırdığı bir yapıya ihtiyaç duyduğunuzda, HTTP taşıma protokolüne ve gerçek bir servise ihtiyacınız vardır. İşte resmi SDK'yı kullanarak tek bir aracı dışa açan minimal bir Python sunucusu:

# /opt/mcp-ops/server.py
from mcp.server.mcpserver import MCPServer
import subprocess

mcp = MCPServer("ops-tools")

@mcp.tool()
def disk_free() -> str:
    """Return `df -h` for the server."""
    out = subprocess.run(["df", "-h"], capture_output=True, text=True)
    return out.stdout

if __name__ == "__main__":
    # Serves Streamable HTTP at /mcp on 127.0.0.1:8000
    mcp.run(transport="streamable-http", host="127.0.0.1", port=8000)

host="127.0.0.1" notuna dikkat edin. Sunucu yalnızca localhost üzerinde dinleme yapar; kimlik doğrulama mekanizması kurulmadan önce tam olarak istenen durum budur, böylece makine dışından kimse doğrudan erişemez. Bu, pip install "mcp[cli]" tarafından bugün çekilen (2026-10-20 itibarıyla 2.3.0) 2.x sürüm SDK'dır. Bu sürümde FastMCP ismi MCPServer olarak değiştirilmiş, host ve port kurucudan run() kısmına taşınmış ve eski mcp.server.fastmcp içe aktarma işlemi artık ModuleNotFoundError hatasıyla başarısız olmaktadır. systemd'nin kararlı bir yorumlayıcı yoluna sahip olması için bunu kendi virtualenv ortamınıza kurun:

sudo useradd --system --home /opt/mcp-ops --shell /usr/sbin/nologin mcp
sudo install -d -o mcp -g mcp /opt/mcp-ops
sudo -H -u mcp python3 -m venv /opt/mcp-ops/.venv
sudo -H -u mcp /opt/mcp-ops/.venv/bin/pip install "mcp[cli]"

Adım 3: systemd ile ayakta tutma

Aracı (agent) ihtiyaç duyduğunda çalışmayan bir araç, hiç olmamasından daha kötüdür. İstemcinin kendisi uzun ömürlü bir süreç olduğunda bu durum daha da kritikleşir: belleğini koruyan ve yeniden başlatmalar arasında zamanlama yapan sürekli çalışan bir aracı, başında kimse yokken bu araçları belirli bir takvimde çağıracaktır; bu nedenle sunucunun da kendi kendine ayağa kalkması gerekir. /etc/systemd/system/mcp-ops.service dosyasını oluşturun:

[Unit]
Description=MCP ops-tools server
After=network.target

[Service]
Type=simple
User=mcp
WorkingDirectory=/opt/mcp-ops
ExecStart=/opt/mcp-ops/.venv/bin/python /opt/mcp-ops/server.py
Restart=on-failure
RestartSec=2
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true

[Install]
WantedBy=multi-user.target

ExecStart içindeki venv Python yolunun mutlak olması zorunludur; yolu /usr/bin/python3 konumuna işaret edin. Süreç ModuleNotFoundError: No module named 'mcp' ile başlar, çünkü sistem yorumlayıcısı pip install dosyanızı görmez. Servisi etkinleştirin ve kontrol edin:

sudo systemctl daemon-reload
sudo systemctl enable --now mcp-ops
sudo systemctl status mcp-ops
curl -si -H 'Accept: application/json, text/event-stream' \
  -H 'Content-Type: application/json' \
  -X POST http://127.0.0.1:8000/mcp

status çıktısı active (running) değerini göstermelidir. curl, gövdesinde bir JSON-RPC hatası ile HTTP/1.1 400 Bad Request yanıtını döndürür. İstek herhangi bir oturum veya geçerli bir JSON yükü taşımamaktadır; tam olarak istenen durum budur: bu, portun yanıt verdiğini ve protokolü konuştuğunu kanıtlar. Connection refused veya boş bir yanıt, sürecin düşündüğünüz yere bağlı olmadığını gösterir; journalctl -u mcp-ops -n 50 dosyasını inceleyin.

Adım 4: TLS ve reverse proxy kurulumu

Sunucu localhost üzerinde dinleme yapar. Dışarıdan erişim sağlamak için TLS sonlandırmasını nginx üzerinde yapmalı ve trafiği içeriye yönlendirmelisiniz. nginx kurulumunu yapın, nginx üzerinde Certbot ve Let's Encrypt kullanarak bir sertifika alın ve ardından location bloğunu yazın. Kritik nokta, tampon belleği (buffering) devre dışı bırakmaktır; çünkü nginx'in varsayılan davranışı yanıt tamamlanana kadar bekletmektir ve bu durum SSE akışını kalıcı olarak durdurur:

server {
    listen 443 ssl;
    server_name mcp.example.com;

    # ssl_certificate lines managed by Certbot

    location /mcp {
        proxy_pass http://127.0.0.1:8000;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        proxy_set_header Host $host;

        # The four lines that make SSE work through nginx:
        proxy_buffering off;
        proxy_cache off;
        proxy_read_timeout 3600s;
        chunked_transfer_encoding off;
    }
}

sudo nginx -t && sudo systemctl reload nginx komutu ile yeniden yükleyin. Eğer halihazırda bir container filosu çalıştırıyorsanız, aynı işlem otomatik TLS özellikli Traefik reverse proxy tarafından sizin yerinize yapılır; bu araç sertifikayı oluşturur ve ana bilgisayar adına göre yönlendirme yapar, sizin ise sadece MCP container'ına etiketleri eklemeniz yeterlidir. Her iki durumda da reverse proxy artık genel port üzerindeki tek bileşendir ve henüz güvenliğini sağlamadığınız bir servise işaret etmektedir. URL'yi herhangi bir yerde kaydettirmeden önce bu güvenlik açığını giderin.

Adım 5: Bu konuyu domine eden güvenlik kuralı

Kimlik doğrulaması yapılmamış bir MCP uç noktasını asla dış dünyaya açmayın. Bir MCP sunucusu salt okunur bir API değildir. Dosyalarınıza, veritabanınıza ve bazen bir kabuğa (shell) erişim sağlayan araçlar sunar. İnternete açık bir /mcp, yapay zeka temsilcinizle aynı yetkilere sahip bir yabancı gibidir: araçlarınızı listeler ve ardından onları çağırır. Buna, kimlik doğrulaması olmayan bir yönetici soketi gibi davranın; çünkü gerçekte olan budur. Çalınan bir jetonun (token) size ne kadara mal olacağı, arkasındaki sunucuya da bağlıdır: openGym antrenman takip uygulamasıyla birlikte gelen salt okunur MCP sunucusu yalnızca eğitim verilerini geri verebilirken, bir dosya sistemi veya kabuk aracı tüm sunucuyu ele geçirmenize olanak tanır.

Tercih sırasına göre üç savunma yöntemi:

  1. Yayınlamayın. Sunucuyu 127.0.0.1 üzerinde tutun ve dizüstü bilgisayarınızdan bir SSH tüneli ile erişin: ssh -L 8000:127.0.0.1:8000 matt@vps komutunu kullanın, ardından istemciyi http://127.0.0.1:8000/mcp adresine yönlendirin. Hiçbir şey dış dünyaya açılmamış olur.
  2. Özel bir ağa yerleştirin. Tünel adresini bir kendi kendine barındırılan WireGuard VPN üzerinde bağlayın ve yalnızca VPN eşlerinin erişmesine izin verin. Genel internet, kapalı bir port görür.
  3. Halka açık olması gerekiyorsa, bir jeton zorunlu tutun. Doğru çözüm, HTTP taşıyıcısının yerel olarak desteklediği MCP OAuth akışıdır. Pratik minimum çözüm ise proxy katmanında kontrol edilen paylaşımlı bir taşıyıcı jetondur; bu yöntem ucuzdur ve rastgele saldırıları tamamen durdurur:
location /mcp {
    if ($http_authorization != "Bearer REPLACE_WITH_LONG_RANDOM") {
        return 401;
    }
    proxy_pass http://127.0.0.1:8000;
    # ...buffering-off block from above...
}

Jetonu openssl rand -hex 32 ile oluşturun ve önünde bunlardan biri olmadan sunucuyu asla 0.0.0.0 adresine bağlamayın. İstemci, jetonu bir başlık (header) olarak gönderir. Claude Code içinde:

claude mcp add --scope project --transport http ops-tools https://mcp.example.com/mcp \
  --header 'Authorization: Bearer ${MCP_TOKEN}'

MCP_TOKEN değişkenini kabuğunuzda ayarlayın, böylece gizli anahtar .mcp.json dosyasına düz metin olarak yazılmaz; Claude Code, ${MCP_TOKEN} değişkenini okuma sırasında ortamdan genişletir. Değişken ayarlanmamışsa, Claude Code boş bir dize eklemez: claude mcp list içinde eksik değişkeni işaretler ve ${MCP_TOKEN} metnini olduğu gibi kullanır. Ayrıca kendi belirlediğiniz bir isim kullanın; çünkü uzak bir sunucunun başlıklarında Claude Code, kendi değişkenlerini ve ANTHROPIC_API_KEY gibi bulut sağlayıcınızın kimlik bilgisi değişkenlerini, ortamınızda bulunan NPM_TOKEN gibi diğer kimlik bilgileriyle birlikte kasıtlı olarak boş okur.

Yukarıdaki her savunma, jetonu zaten elinde bulunduran temsilciden ziyade uç noktayı korur; bu da sorunun diğer yarısıdır: Eğer istemciniz DeepSeek Harness ise, bir temsilcinin hangi araçları çağırabileceğini sınırlayan ve araç çıktılarını enjekte edilen komutlar için tarayan eklentiler bu tarafı kapsar.

Adım 6: MCP Inspector ile hata ayıklama

Sunucu düzgün çalışmadığında tahmin yürütmek yerine, resmi web tabanlı test istemcisi olan Inspector ile doğrudan müdahale edin. stdio sunucusu için, aracı tarafından çalıştırılan komutun aynısını verin:

npx @modelcontextprotocol/inspector \
  npx -y @modelcontextprotocol/server-filesystem /tmp

Arayüzünü http://localhost:6274 üzerindeki bir web sunucusundan servis eder ve MCP_INSPECTOR_API_TOKEN sorgu dizisini içeren bir URL yazdırır; adresi hafızadan yazmak yerine bu bağlantıyı açın. v2 sürümünden itibaren (2026-10-20 itibarıyla güncel sürüm 2.11.0), arka uç her yüklemede belirteci (token) sayfaya enjekte eder; böylece sayfa yenilendiğinde çalışmaya devam eder ve belirteç, süreç başlatabilen /api/* rotalarını korur. 6277 üzerindeki ayrı v1 proxy kaldırılmıştır, ancak web sunucusu tek dinleyici değildir: v2 ayrıca MCP_SANDBOX_PORT (varsayılan olarak 6275) üzerinde MCP Apps için bir sandbox ve MCP_APP_ORIGIN_PORT (varsayılan olarak 6278) üzerinde, arayüz kaynağı _meta.ui.domain bildiren tüm MCP Uygulamalarını sunan özel bir uygulama kökenli sunucu başlatır. Inspector'a bir SSH tüneli üzerinden erişiyorsanız veya bir container içinde çalıştırıp Uygulamalar sekmesine ihtiyaç duyuyorsanız, 6274 ile birlikte 6275 ve 6278 portlarını da yönlendirin. Bağlanın, Tools sekmesini açın, bir araç seçin, gerçek argümanları girin ve çağırın. Inspector'da çalışıyor ancak araçta başarısız oluyorsa, hata sunucuda değil, istemci yapılandırmanızdadır. Uzak HTTP sunucusu için, Inspector'ı komutsuz başlatın, Streamable HTTP taşıyıcısı ve https://mcp.example.com/mcp ile bir sunucu ekleyin, ayarlarına Authorization başlığını koyun ve bağlanın; bu, herhangi bir aracı dahil etmeden önce kimlik doğrulamanın ve proxy'nin doğru olduğunu kanıtlamanın en hızlı yoludur. Inspector, başlıkları sunucu kataloğuna tam olarak yazıldığı gibi kaydeder, bu nedenle söz konusu belirteç artık ~/.mcp-inspector/mcp.json içinde de yer alır.

Sunucuları güncel tutma

MCP hızlı gelişen bir yapıya sahiptir, bu nedenle yamaları bir takvime göre uygulayın. Sabitlenmemiş bir npx -y ile başlatılan Node sunucuları, npx'in çözümlediği herhangi bir sürümü çalıştırır: yerel projede varsa yüklü olan sürümü, yoksa npm önbelleğine yüklediği bir kopyayı kullanır. -y yalnızca yükleme istemini atlar, güncellemeyi zorunlu kılmaz; bu nedenle ne en son sürümü takip edebilirsiniz ne de hangi sürümü çalıştırdığınızdan emin olabilirsiniz. Bir sunucu önem kazandığında, test ettiğiniz sürümü sabitleyin; bu sürümü npm view @modelcontextprotocol/server-filesystem version dosyasından okuyun ve .mcp.json içindeki paket adına ekleyin (@modelcontextprotocol/server-filesystem@<version>), ardından güncellemeleri bilinçli olarak yapın. systemd altındaki Python sunucuları, sudo -H -u mcp /opt/mcp-ops/.venv/bin/pip install -U "mcp[cli]" ve ardından sudo systemctl restart mcp-ops komutlarıyla güncellenir. Büyük bir sürüm yükseltmesi yapmadan önce sürüm notlarını okuyun: 1.x sürümünden 2.x Python SDK sürümüne geçiş, import aşamasında 1.x kodunu bozar. SDK'nın kendi geçiş kılavuzu, geçişi tamamlayana kadar "mcp[cli]<2" gibi bir <2 üst sınırı belirlemenizi önerir. Yükseltme yaparken SDK'nızın hedeflediği spesifikasyon revizyonunu izleyin; SSE'den Streamable-HTTP sınırına geçiş, istemcilerinizin talep etmesi gereken taşıma protokolünü değiştirebilir.

Hata modları ve karşılaşacağınız dizgeler

Ajan sunucunun başarısız olduğunu bildiriyor. claude mcp list, ✘ Failed to connect dizgesini yazdırır ve güncel sürümler hata detayını bu satıra ekler. claude --debug komutunu çalıştırdığınızda genellikle Error: spawn npx ENOENT hatasını görürsünüz; bu, komutun ajanın PATH dizininde bulunmadığı anlamına gelir. Çalışma zamanı eksiktir veya ajanın aradığı yerde değildir: Node yüklü değildir, npx mevcut değildir veya doğrudan isimle çağrılan bir virtualenv Python ortamı söz konusudur. Komutu mutlak yol (absolute path) ile güncelleyin veya çalışma zamanını yükleyip yeniden bağlanın.

Bir stdio sunucusu bağlanıyor ancak hemen ardından bağlantıyı kesiyor. İstemci, Unexpected token 'S', "Server sta"... is not valid JSON veya Failed to parse message gibi bir JSON ayrıştırma hatası günlüğü tutar. Bunun nedeni her zaman aynıdır: sunucu stdout kanalına bir günlük satırı yazmıştır. Stdio üzerinde stdout, JSON-RPC kanalıdır; bu nedenle buraya yazılan herhangi bir metin akışı bozar ve el sıkışma (handshake) başarısız olur. Node ortamında console.log stdout'a yazar, bunun yerine console.error kullanın. Python'da doğrudan kullanılan print() stdout'a çıktı verir; günlükleri sys.stderr olarak yapılandırılmış logging ile yazın veya file=sys.stderr parametresini kullanın. Kural kesindir: stdio üzerinde stdout'ta yalnızca JSON-RPC verisi bulunmalı, insan tarafından okunabilir tüm çıktılar stderr'e gönderilmelidir.

Uzak sunucu zaman aşımına uğruyor veya el sıkışma sırasında bağlantıyı kapatıyor. İstemci MCP error -32000: Connection closed hatası verir veya Inspector Connect aşamasında takılı kalır ve araçları listelemez. Nginx arkasındaki bu durum tamponlama (buffering) kaynaklıdır: proxy, SSE akışını anlık iletmek yerine tutar, bu yüzden istemci asla gelmeyecek bir yanıtı bekler. proxy_buffering off; ayarını (ve 4. adımdaki bloğun geri kalanını) location dosyasına ekleyin. Genel URL üzerinde curl -N ile doğrulama yapın; olay verilerinin sonunda tek seferde değil, kademeli olarak geldiğini görmelisiniz.

Kimlik doğrulama reddediliyor. İstemci Error POSTing to endpoint (HTTP 401) veya doğrudan 401 Unauthorized hatası bildirir. Ya başlık eksiktir, ya token yanlıştır ya da değişken genişletilmemiştir; bu yaygın bir tuzaktır. İstemci yapılandırmayı okuduğunda MCP_TOKEN ayarlanmamışsa, Claude Code claude mcp list içinde eksik değişken uyarısı verir ve literal metni gönderir; bu durumda Nginx Bearer ${MCP_TOKEN} görür. Claude Code'un, bulut sağlayıcınızın veya ortamınızın diğer kimlik bilgilerinden biriyle aynı adı taşıyan bir değişken boş okunur ve Nginx Bearer değerini boş görür. Değişkeni echo ile yazdırın, başlığı yeniden ekleyin ve baytların Nginx if içindeki token ile tam olarak eşleştiğini doğrulayın.

Servis systemd altında başlamıyor. journalctl -u mcp-ops komutu ModuleNotFoundError: No module named 'mcp' çıktısını verir, ExecStart ise venv yorumlayıcısı yerine sistem Python'ını işaret eder. Veya Address already in use hatası alınırsa, başka bir süreç 8000 numaralı portu tutuyordur; bunu sudo ss -ltnp | grep 8000 ile bulun.

FAQ

MCP sunucusu tam olarak nedir?

Model Context Protocol üzerinden JSON-RPC 2.0 kullanarak bir yapay zeka istemcisine araçlar ve kaynaklar sunan bir programdır. Yapay zeka modeli aracı kendisi çalıştırmaz; istemcisinden talep eder, istemci MCP sunucusunu çağırır, sunucu ise işlemi gerçekleştirip sonucu döndürür. Protokol standart olduğu için, bir sunucu Claude Code, Claude Desktop veya Gemini CLI gibi uyumlu olan tüm istemcilerle çalışır.

stdio ve HTTP taşıma yöntemleri arasındaki fark nedir?

Bir stdio sunucusu, istemci tarafından bir alt süreç (child process) olarak başlatılır ve stdin/stdout üzerinden iletişim kurar; bu nedenle tek bir makinede tek bir istemciyle çalışır, ağ veya kimlik doğrulama gerektirmez. HTTP sunucusu ise birçok istemcinin aynı anda erişebildiği, uzun süre çalışan bir ağ servisidir; bu yüzden TLS ve kimlik doğrulama gerektirir. Yerel ve tek kullanıcılı araçlar için stdio; paylaşılan veya kalıcı yapılar için ise HTTP (mevcut sunucularda Streamable HTTP) kullanın.

Uzak bir MCP sunucusunu nasıl güvenli hale getiririm?

Sunucunun dosyalarınıza, veritabanınıza veya kabuğunuza erişim sağladığını varsayın ve asla kimlik doğrulaması olmadan dış dünyaya açmayın. En güvenli yöntem, sunucuyu localhost üzerinde tutmak ve bir SSH tüneli veya özel bir VPN üzerinden erişmektir; eğer herkese açık olması gerekiyorsa, bir bearer token veya MCP OAuth akışını zorunlu kılan bir reverse proxy arkasına yerleştirin. Token'ı openssl rand -hex 32 ile oluşturun ve önünde bu güvenlik katmanlarından biri olmadan sunucuyu asla 0.0.0.0 adresine bağlamayın.

Başlamayan bir sunucuda hata ayıklamasını nasıl yaparım?

Öncelikle claude mcp list ve ✘ Failed to connect çıktılarını kontrol edin; spawn ... ENOENT hatası, komutun veya çalışma zamanının eksik olduğu anlamına gelir; bu durumda yolu düzeltin veya ilgili paketi kurun. Eğer bağlantı kuruluyor ancak JSON ayrıştırma hatasıyla düşüyorsa, sunucu stdout'a log yazıyor ve JSON-RPC akışını bozuyor demektir; tüm loglama işlemlerini stderr'e yönlendirin. Diğer tüm durumlar için, sunucuyu izole bir şekilde çalıştıran MCP Inspector altında aynı komutu çalıştırın; böylece sunucu hatası ile istemci yapılandırma hatasını birbirinden ayırabilirsiniz.