Mert Özen Her Satırda Daha İleri
Yapay Zeka Claude Code — #08

Claude Code'a MCP Server Bağlamak: Bookstore MCP Server'ı, Veritabanı ve Tarayıcı

Mert Özen 15 Kas 2026 10 dk 3 görüntülenme
Claude Code'a MCP Server Bağlamak: Bookstore MCP Server'ı, Veritabanı ve Tarayıcı

Claude Code'a MCP server'ı claude mcp add ile ya da ekip için repo kökündeki .mcp.json ile bağlarsın; proje server'ları interaktif session'da onay ister, claude -p'de sorulmadan yüklenir. Scope'lar, ${VAR} genişletmesi, tool search ve çıktı sınırları; Bookstore için C# MCP server'ı, salt okunur login ve DBHub ile SQL Server, Playwright MCP ve ui-tester subagent'ı.

Sürüm notu: Bu yazı Claude Code 2.1.325'i (13 Kasım 2026) anlatır; scope'lar, .mcp.json formatı, onay ve çıktı sınırları 15 Kasım 2026'da code.claude.com/docs'taki MCP (Model Context Protocol; dış araç ve veri kaynaklarına bağlanma protokolü) sayfaları Connect Claude Code to tools via MCP ve Control MCP server access for your organization ile Use Claude Code with Chrome ve Manage costs effectively sayfalarından kontrol edilmiştir. Bu yazıda resmî belgelerden yararlanılmıştır. .mcp.json'daki DBHub 1.6.1 ve @playwright/mcp 0.0.85 server'ları yerelde Node.js 24 ile başlatılıp tool listeleri alınmış, DBHub'ın readonly ayarı bir SQLite örneğiyle denenmiş, SQL script'i ScriptDom ile ayrıştırılmıştır.

Önce Tahmin Et

Ayşe, sitedeki serilerin ortak örnek uygulaması Bookstore'da (bir online kitapçı) Claude Code'un veritabanına doğrudan bakabilmesi için bir MCP server'ı ekledi. Connection string'i sa kullanıcısıyla .mcp.json'a yazdı ve commit'ledi. Emre repo'yu çektiğinde hiçbir şey sormadan çalışacağını, CI'daki claude -p koşusunun ise server'ı hiç başlatmayacağını düşündü.

Tahminin ne? Ekip arkadaşının makinesinde .mcp.json'daki server soru sormadan bağlanır mı? claude -p'de ne olur? Ve şifrenin doğru yeri neresi? İlk iki cevap Üretimde Dikkat bölümünde, üçüncüsü SQL Server bölümünde.

MCP Claude Code'a Ne Katıyor?

MCP server'ı Claude'a yeni tool'lar veriyor; Claude Code bunları mcp__<server>__<tool> adıyla görüyor ve permission kuralları da hook matcher'ları da bu adı kullanıyor. Protokolün kendisini ve C# ile server yazmayı AI Agent'ları ve MCP serisinde anlattık; burada yalnız Claude Code tarafı var.

Belgelere göre tool search varsayılan açık: session başında yalnız tool adları ve server talimatları yükleniyor, tool tanımları Claude ihtiyaç duyunca geliyor. Bu yüzden server eklemek context'i eskisi kadar şişirmiyor. Yine de Manage costs effectively sayfası gh, az gibi CLI araçlarını hâlâ daha ucuz buluyor, çünkü onların hiçbir tool listesi yok ve Claude komutu doğrudan çalıştırıyor. Bookstore'da kural basit: dotnet, git, gh varken MCP ekleme; MCP'yi CLI'ı olmayan ya da yetkisini daraltmak istediğin kaynaklar için kullan.

claude mcp add ve Scope'lar

Server eklemenin iki yolu var: claude mcp add komutu ya da dosyayı elle yazmak. Komutun temel biçimi:

claude mcp add --transport http <name> <url>
claude mcp add --transport stdio --scope project <name> -- <command> [args...]
claude mcp list
claude mcp get <name>
claude mcp remove <name>

stdio'da --, Claude Code'un kendi seçeneklerini server'ın komutundan ayırıyor; ondan sonraki her şey server'a olduğu gibi gidiyor. Scope, server'ın nerede saklandığını ve kimin göreceğini belirliyor:

ScopeNerede dururKim görür
local (varsayılan)~/.claude.json, bu projenin altındaYalnız sen, yalnız bu projede
projectRepo kökündeki .mcp.jsonRepo'yu çeken herkes
user~/.claude.jsonYalnız sen, bütün projelerde

Aynı ad birden fazla yerde varsa önce local, sonra project, sonra user kazanıyor ve alanlar birleştirilmiyor, kazanan kaydın tamamı kullanılıyor. Dikkat: MCP'deki "local scope" .claude/settings.local.json değil, ev dizinindeki ~/.claude.json. Session içinde /mcp her server'ın durumunu gösteriyor; claude mcp list ise ✔ Connected, ! Needs authentication ya da henüz onaylanmamış proje server'ları için ⏸ Pending approval gibi durumlar yazıyor.

Bookstore: .mcp.json ve C# Server

Ekip için üç server'ı repo kökündeki .mcp.json'a, yani project scope'a koyuyoruz:

{
  "mcpServers": {
    "bookstore": {
      "type": "stdio",
      "command": "dotnet",
      "args": ["${CLAUDE_PROJECT_DIR:-.}/src/Bookstore.Mcp.Server/bin/Debug/net10.0/Bookstore.Mcp.Server.dll"],
      "env": {
        "Bookstore__CustomerId": "7"
      }
    },
    "bookstore-db": {
      "type": "stdio",
      "command": "node",
      "args": [
        "${CLAUDE_PROJECT_DIR:-.}/tools/mcp/node_modules/@bytebase/dbhub/dist/index.js",
        "--transport", "stdio",
        "--config=${CLAUDE_PROJECT_DIR:-.}/tools/mcp/dbhub.toml"
      ],
      "env": {
        "BOOKSTORE_RO_PASSWORD": "${BOOKSTORE_RO_PASSWORD}"
      }
    },
    "playwright": {
      "type": "stdio",
      "command": "node",
      "args": [
        "${CLAUDE_PROJECT_DIR:-.}/tools/mcp/node_modules/@playwright/mcp/cli.js",
        "--browser", "msedge",
        "--isolated",
        "--allowed-origins", "http://localhost:4200"
      ]
    }
  }
}

08-mcp-servers-tr.png

bookstore, AI Agent'ları ve MCP serisinin dokuzuncu yazısındaki C# stdio server'ı: search_books, check_stock ve get_order_status tool'ları var ve repo'da src/Bookstore.Mcp.Server altında duruyor. dotnet run yerine derlenmiş DLL'i (derlenmiş .NET assembly dosyası) çalıştırıyoruz; o yazıda gördüğümüz gibi stdio'da stdout yalnız protokol mesajlarına ait ve build çıktısının oraya karışmasını istemiyoruz. Session'dan önce bir kez dotnet build src/Bookstore.Mcp.Server yeterli.

${CLAUDE_PROJECT_DIR:-.} kalıbı belgelerden: Claude Code bu değişkeni stdio server'ın kendi ortamına koyuyor ama kendi ortamında tutmuyor, bu yüzden .mcp.json'daki command ve args içinde varsayılan değerle yazılması gerekiyor. .mcp.json'da command, args, env, url ve headers değerlerinde ${VAR} ve ${VAR:-default} genişletmesi destekleniyor.

Node.js tabanlı iki server'ı npx -y ile değil, repo'da sürümü sabitlenmiş paketlerden node ile başlatıyoruz. Böylece her session'da internetten paket indirilmiyor ve herkes aynı sürümü kullanıyor. tools/mcp/package.json:

{
  "name": "bookstore-mcp-tools",
  "private": true,
  "description": "MCP servers that Claude Code starts for the Bookstore repository",
  "dependencies": {
    "@bytebase/dbhub": "1.6.1",
    "@playwright/mcp": "0.0.85"
  }
}

Yeni gelen geliştirici bir kez npm install --prefix tools/mcp çalıştırıyor; node_modules .gitignore'da. DBHub 1.6.1'in package.json'ı Node.js 22.5 ve üstünü istiyor.

Bookstore: Salt Okunur SQL Server

Tahmindeki üçüncü sorunun cevabı iki katmanlı. Birincisi veritabanının kendisi: Claude'un kullandığı login yalnız okuyabilmeli. tools/mcp/sql/create-readonly-login.sql:

/* Read-only login for the bookstore-db MCP server. Local development databases only.
   sqlcmd -S localhost -i tools/mcp/sql/create-readonly-login.sql -v ReadOnlyPassword="..." */
CREATE LOGIN bookstore_readonly WITH PASSWORD = '$(ReadOnlyPassword)';
GO
USE BookstoreDb;
GO
CREATE USER bookstore_readonly FOR LOGIN bookstore_readonly;
ALTER ROLE db_datareader ADD MEMBER bookstore_readonly;
GO

Şifre script'te yok; sqlcmd'nin -v parametresiyle çalışma anında veriliyor. db_datareader rolü veritabanındaki bütün tablolarda SELECT yetkisi veriyor ve başka hiçbir şey vermiyor. Bu login'i yalnız yerel geliştirme veritabanında aç; production'a bağlanan bir MCP server'ı burada konu dışı.

İkinci katman DBHub'ın kendi ayarı. Claude Code belgelerinin MCP sayfasındaki veritabanı örneği de DBHub'ı kullanıyor. tools/mcp/dbhub.toml:

# Yerel SQL Server, salt okunur login (tools/mcp/sql/create-readonly-login.sql).
# Şifre BOOKSTORE_RO_PASSWORD ortam değişkeninden gelir.
[[sources]]
id = "bookstore"
dsn = "sqlserver://bookstore_readonly:${BOOKSTORE_RO_PASSWORD}@localhost:1433/BookstoreDb"

[[tools]]
name = "execute_sql"
source = "bookstore"
readonly = true
max_rows = 200

[[tools]]
name = "search_objects"
source = "bookstore"

readonly = true ile DBHub her ifadeyi okuma komutlarından oluşan bir allowlist'e göre kontrol ediyor ve belgelerine göre veritabanının kendi read-only modunu da kullanıyor; max_rows tek sorgunun döndürebileceği satırı sınırlıyor. Aynı [[tools]] ayarını yerelde bir SQLite örneğiyle DBHub 1.6.1'e verdiğimizde DELETE ifadesi READONLY_VIOLATION koduyla reddedildi, tablo değişmedi. Yine de asıl sınır login: DBHub'ın sınıflandırıcısı bir hata yaparsa db_datareader yazmaya izin vermiyor.

Şifre .mcp.json'a da dbhub.toml'a da girmiyor. .mcp.json'daki "BOOKSTORE_RO_PASSWORD": "${BOOKSTORE_RO_PASSWORD}" satırı değeri senin ortam değişkeninden alıp server sürecine geçiriyor, DBHub da TOML (INI benzeri, okunması kolay bir configuration formatı) dosyasındaki ${...} ifadesini kendi ortamından dolduruyor. Şifrede @ ya da : gibi karakterler varsa DSN (Data Source Name; veritabanına bağlanma adresi) içinde URL encoding gerekiyor.

Bookstore: Tarayıcıyla Angular Testi

Angular arayüzünü Claude'a denetletmenin iki yolu var. Claude in Chrome entegrasyonu (claude --chrome) senin gerçek Chrome ya da Edge'ini kullanıyor; oturum açtığın sitelere erişebiliyor, doğrudan bir Anthropic aboneliği ve /login istiyor, API key ile çalışmıyor ve WSL'de (Windows Subsystem for Linux; Windows içinde çalışan Linux ortamı) desteklenmiyor. Playwright MCP ise ayrı bir tarayıcı süreci açıyor. Bookstore'da ikincisini seçtik: --isolated profili diske yazmıyor, yani senin oturumların ve çerezlerin o tarayıcıda yok. Chrome DevTools MCP gibi alternatifler Browser DevTools serisinin onuncu yazısında.

--allowed-origins tarayıcının istek atabileceği origin'leri http://localhost:4200 ile sınırlıyor, ama Playwright MCP'nin kendi belgesi bunun bir güvenlik sınırı olmadığını ve redirect'leri etkilemediğini açıkça yazıyor. Server'ın tool listesinde 25 tool var; aralarında browser_run_code_unsafe ve browser_file_upload da bulunuyor. Bu ikisini .claude/settings.json'da kapatıyor, salt okunur tool'lara da izin veriyoruz; aşağıdaki satırlar mevcut allow ve deny listelerine ekleniyor:

{
  "permissions": {
    "allow": [
      "mcp__bookstore__search_books",
      "mcp__bookstore__check_stock",
      "mcp__bookstore-db__search_objects"
    ],
    "deny": [
      "mcp__playwright__browser_run_code_unsafe",
      "mcp__playwright__browser_file_upload"
    ]
  }
}

Ekran görüntüleri ve DOM (Document Object Model; sayfanın tarayıcıdaki ağaç yapısı) snapshot'ları büyük çıktılar; altıncı yazıdaki mantıkla tarayıcı işini bir subagent'a veriyoruz. .claude/agents/ui-tester.md:

---
name: ui-tester
description: Walks through a flow of the running Angular client at http://localhost:4200 in a browser through the playwright MCP server and reports console errors and the step that failed. Use after UI changes while the dev server is running.
tools: Read, Grep, Glob, mcp__playwright__*
model: sonnet
mcpServers:
  - playwright
---

You test the Bookstore Angular client in a browser. You never edit files.

Open only pages under http://localhost:4200. If the page does not load,
report that the dev server is down and stop.

For the flow in the task (for example: search for "Dune", add it to the cart,
open the cart):
1. Do each step with the browser tools and take a snapshot after it.
2. Read the console messages after each step.
3. Stop at the first step that fails.

Report, at most 20 lines: the steps that passed, the failing step with the
expected and actual result, and every console error with its source file.

mcpServers'ta adla verilen server ana session'ın bağlantısını paylaşıyor; tools listesindeki mcp__playwright__* de subagent'a o server'ın bütün tool'larını açıyor. Server'ı ana konuşmadan tamamen uzak tutmak istersen belgelerin önerisi onu .mcp.json yerine subagent frontmatter'ında inline tanımlamak; bu durumda proje subagent'ının inline server'ı ancak workspace trust onayından sonra bağlanıyor.

Büyük Çıktılar, Uzun Çağrılar ve MCP Task'ları

Bir MCP tool'unun çıktısı 10.000 token'ı geçtiğinde Claude Code uyarı veriyor; varsayılan üst sınır 25.000 token ve MAX_MCP_OUTPUT_TOKENS ile değişiyor. Sınırı geçen başarılı bir sonuç konuşmaya girmiyor, session klasöründe bir dosyaya yazılıyor ve Claude gerektiğinde o dosyayı okuyor. Tool kendi sınırını bildirmemişse 50.000 karakteri geçen metin sonuçları da token sayısından bağımsız olarak dosyaya gidiyor. max_rows = 200 bu yüzden yalnız güvenlik değil, context ayarı da.

Ana konuşmadaki bir MCP çağrısı iki dakikadan uzun sürerse arka plana alınıyor ve sonucu bir görev bildirimi olarak geliyor; /tasks'ta görünüyor. Server MCP tasks uzantısını destekliyorsa iş server'da çalışmaya devam ediyor ve uzak bir server'da session'dan çıksan bile sürüyor; bu özellik belgelere göre v2.1.304'ten beri terminalde public beta.

Üretimde Dikkat

Tahmindeki ilk iki sorunun cevabı belgelerde net. İnteraktif session'da Claude Code .mcp.json'daki proje server'larını kullanmadan önce onay istiyor; onaylanmamış server claude mcp list'te ⏸ Pending approval görünüyor. Repo'ya commit'lenen enableAllProjectMcpServers gibi bir ayar güvenilmeyen klasörde yok sayılıyor; yani klonlanan bir repo kendi server'larını kendisi onaylayamıyor. Ama claude -p, Agent SDK ve cloud session'larında bu soruyu gösterecek kimse olmadığı için proje server'ları sorulmadan yükleniyor. Yazmadığın bir repo'da claude -p çalıştıracaksan server'ı disabledMcpjsonServers ile kapat ya da --strict-mcp-config ile yalnız kendi verdiğin configuration'ı yükle.

Uzak server'ların url ve headers değerlerinde Claude Code kendi kimlik bilgilerini, örneğin ANTHROPIC_API_KEY'i, genişletmiyor ve boş okuyor; bir .mcp.json bu değişkenleri başka bir server'a gönderemiyor. Server'ın ihtiyacı olan secret'ı kendi adını verdiğin bir değişkenle geçir.

Güvenmediğin bir server'ın tool açıklamaları Claude'un context'ine giriyor ve talimat taşıyabiliyor. Tool poisoning ve least privilege'ın derin anlatımı AI Agent'ları ve MCP serisinin on üçüncü yazısında. Organizasyon tarafında managed-mcp.json ile sabit bir server seti dağıtılabiliyor, allowedMcpServers ve allowManagedMcpServersOnly ile de yalnız onaylı server'lara izin verilebiliyor; bu ayarlar on birinci yazıda.

Sık Düşülen Tuzaklar

.mcp.json'a şifre yazmak. Dosya commit'leniyor; secret ortam değişkeninden gelmeli.

Yetkili kullanıcıyla bağlanmak. sa ya da db_owner ile bağlı bir server'da DBHub'ın readonly ayarı tek koruma kalıyor; veritabanı login'ini daralt.

url var ama type yok. Belgelere göre type alanı olmayan kayıt stdio sayılıyor; url verdiğin bir kayıtta "type": "http" yazmazsan server atlanıyor.

CLI'ı olan iş için MCP eklemek. gh ve dotnet zaten var; her yeni server bir onay, bir güven kararı ve bir bakım yükü.

Küçük Bir Deneme

★☆☆ npm install --prefix tools/mcp çalıştır, Claude Code'u başlat, /mcp'de üç server'ın durumuna bak ve claude mcp list çıktısıyla karşılaştır.

★★☆ bookstore-db server'ıyla "Book tablosunun index'lerini listele" iste. Sonra DELETE içeren bir sorgu iste ve reddin DBHub'dan mı, veritabanından mı geldiğini hata metninden çıkar.

★★★ ui-tester'ı .mcp.json'daki server'a bağlamak yerine Playwright server'ını subagent frontmatter'ında inline tanımla. Ana session'da /context ve tool listesindeki farkı not et.

Buraya kadar her şey tek bir session ve tek bir checkout'taydı. Dokuzuncu yazıda claude --worktree ile aynı repo'da paralel session'lar açacak, Desktop uygulamasına, claude.ai/code'daki cloud session'larına ve işleri mobilden takip etmeye geçeceğiz.