Skip to content
~/sph.sh

Model Context Protocol: Production-Ready AI Entegrasyonları Geliştirmek

MCP'nin AI tool entegrasyonunu nasıl standartlaştırdığını, TypeScript örnekleriyle server geliştirme, güvenlik yönetimi ve production performans optimizasyonunu öğren.

Entegrasyon Problemini Anlamak

AI entegrasyonları üzerinde çalışırken bir pattern ortaya çıktı: her yeni AI modeli, her veri kaynağı ve tool için custom bağlantılara ihtiyaç duyuyor. Matematik acımasız; M model çarpı N tool, M×N custom implementation demek. Takımların Slack, GitHub ve database'ler için haftalarca bespoke entegrasyon geliştirdiğini, AI provider değiştiğinde tüm süreci tekrarladığını gördüm.

Geleneksel API'ler bunun için tasarlanmamış. REST endpoint'leri tahmin edilebilir request pattern'leri bekliyor, ama AI agent'ları conversation başına yüzlerce request üretiyor, latency gereksinimleri çok farklı. GraphQL flexible query'lerde yardımcı olsa da, dynamic tool discovery veya multiple invocation'lar arası session management için built-in desteği yok.

Model Context Protocol (MCP) bunu entegrasyon katmanını standartlaştırarak çözüyor. Her AI model ve service kombinasyonu için custom bağlantı kurmak yerine, MCP universal bir protocol sağlıyor; USB-C'nin device bağlantılarını standartlaştırması gibi.

MCP Aslında Nedir

MCP, AI-to-service communication için bir protocol specification. Anthropic tarafından Kasım 2024'te başlatıldı. İlk yılında OpenAI, Google DeepMind ve SAP, Oracle, Docker gibi enterprise platformlar tarafından adopt edildi. Protocol, AI sistemlerinin tool'ları nasıl keşfettiğini ve invoke ettiğini, resource'lara nasıl eriştiğini ve session'ları nasıl yönettiğini tanımlıyor.

İşte architecture:

Core primitive'ler:

  1. Tools: AI'ın invoke edebileceği executable function'lar (model-controlled)
  2. Resources: Application'ın yönettiği data source'lar (application-controlled)
  3. Prompts: Interaction'ları yapılandırmak için reusable template'ler

Transport seçenekleri:

  • stdio: stdin/stdout üzerinden local subprocess communication (development)
  • Streamable HTTP: Optional SSE streaming ile remote HTTP POST (production)

Protocol tüm message exchange için JSON-RPC 2.0 kullanıyor, transport ne olursa olsun consistent communication pattern'leri sağlıyor.

İlk MCP Server'ını Geliştirmek

Filesystem operation'larını expose eden minimal viable bir server geliştirelim. Bu core concept'leri gösteriyor: server initialization, tool registration, schema validation ve security constraint'ler.

typescript
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";import { z } from "zod";import { readdir, readFile } from "fs/promises";import { join } from "path";
// Server'ı metadata ile initialize etconst server = new McpServer({  name: "filesystem-server",  version: "1.0.0",});
// Directory içeriğini listeleme tool'userver.registerTool(  "list_directory",  {    title: "List Directory",    description: "Directory içeriğini listele",    inputSchema: {      type: "object",      properties: {        path: {          type: "string",          description: "Listelenecek directory path"        }      },      required: ["path"]    }  },  async ({ path }) => {    // Güvenlik: Path'in allowed directory içinde olduğunu kontrol et    const allowedDir = process.env.HOME || "/";    const fullPath = join(allowedDir, path);
    if (!fullPath.startsWith(allowedDir)) {      throw new Error("Erişim reddedildi: Path allowed directory dışında");    }
    const entries = await readdir(fullPath, { withFileTypes: true });
    return {      content: [        {          type: "text",          text: JSON.stringify(            entries.map(entry => ({              name: entry.name,              type: entry.isDirectory() ? "directory" : "file"            })),            null,            2          ),        },      ],    };  });
// Dosya içeriğini okuma tool'userver.registerTool(  "read_file",  {    title: "Read File",    description: "Dosya içeriğini oku",    inputSchema: {      type: "object",      properties: {        path: {          type: "string",          description: "Okunacak file path"        }      },      required: ["path"]    }  },  async ({ path }) => {    // Path validate et - traversal yok, home directory içinde olmalı    if (path.includes("..") || !path.startsWith(process.env.HOME || "/")) {      throw new Error("Geçersiz path");    }    try {      const content = await readFile(path, "utf-8");      return {        content: [          {            type: "text",            text: content,          },        ],      };    } catch (error) {      console.error(`Dosya okuma başarısız: ${error.message}`);      return {        content: [          {            type: "text",            text: `Dosya okuma hatası: ${error.message}`,          },        ],        isError: true,      };    }  });
// Server'ı stdio transport ile başlatasync function main() {  const transport = new StdioServerTransport();  await server.connect(transport);  console.error("Filesystem MCP server stdio üzerinde çalışıyor");}
main().catch(console.error);

Kritik implementation detayları:

  • stderr'e loglama: stdout JSON-RPC message'lar için rezerve. stdout'a yazmak protocol'ü bozuyor.
  • Zod validation: Her tool parametresi schema validation gerektiriyor. AI-generated input'lara güvenilemez.
  • Path sandboxing: File operation'ları security constraint'leri code ile enforce etmeli, tool description'larla değil.
  • Error handling: Server'ı çalışır durumda tutmak için exception throw etmek yerine error content döndür.

Bu server'ı MCP Inspector ile test et:

bash
npx @modelcontextprotocol/inspector node dist/filesystem-server.js

Resources vs Tools: Farkı Anlamak

Tool'lar ve resource'lar farklı problemleri çözüyor. Bunları karıştırmak inefficient implementation'lara yol açıyor.

Tools (model-controlled):

  • AI ne zaman invoke edeceğine karar veriyor
  • Side effect'leri olabilir (create, update, delete)
  • Action'lar ve operation'lar için tasarlanmış
  • Örnekler: send_email, create_database, deploy_service

Resources (application-controlled):

  • Application access ve discovery'yi yönetiyor
  • Read-only, side effect yok
  • Data retrieval için tasarlanmış
  • Örnekler: file contents, database record'ları, API documentation

İşte bir resource implementation:

typescript
import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
// URI parametreli resource template kaydetserver.registerResource(  "file-contents",  new ResourceTemplate("file://{filepath}", { list: undefined }),  {    title: "Dosya İçeriği",    description: "Belirli bir dosyanın içeriğini oku",    mimeType: "text/plain",  },  async (uri, { filepath }) => {    // filepath'i validate et    const allowedDir = process.env.HOME || "/";    if (!filepath.startsWith(allowedDir)) {      throw new Error("Erişim reddedildi");    }
    const content = await readFile(filepath, "utf-8");    return {      contents: [        {          uri: uri.href,          mimeType: "text/plain",          text: content,        },      ],    };  });

Temel fark: tool'lar AI'ın function listesinde görünüyor ve conversation context'e göre invoke edilebiliyor. Resource'lar application'ın URI ile explicit request'i gerektiriyor.

Çoklu MCP Server'ları Yönetmek

Production application'ları genelde birden fazla MCP server'a bağlanıyor; biri GitHub operation'ları için, diğeri database'ler için, üçüncüsü Slack notification'ları için. Bu dikkatli tool namespacing ve connection management gerektiriyor.

typescript
import { Client } from "@modelcontextprotocol/sdk/client/index.js";import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
class MultiServerClient {  private clients: Map<string, Client> = new Map();
  async addServer(name: string, command: string, args: string[]) {    const transport = new StdioClientTransport({      command,      args,      stderr: "inherit",    });
    const client = new Client(      {        name: "multi-client",        version: "1.0.0",      },      {        capabilities: {          roots: { listChanged: true },          sampling: {},        },      }    );
    await client.connect(transport);    this.clients.set(name, client);
    console.error(`${name} server'a bağlanıldı`);    return client;  }
  async discoverAllTools() {    const allTools = new Map();
    for (const [serverName, client] of this.clients) {      const { tools } = await client.listTools();
      tools.forEach(tool => {        // Conflict'leri önlemek için tool'ları server ile namespace'le        allTools.set(`${serverName}:${tool.name}`, {          ...tool,          server: serverName,        });      });    }
    return allTools;  }
  async callTool(serverName: string, toolName: string, args: any) {    const client = this.clients.get(serverName);    if (!client) {      throw new Error(`Server ${serverName} bulunamadı`);    }
    return await client.callTool({ name: toolName, arguments: args });  }}
// Kullanımconst mcpClient = new MultiServerClient();await mcpClient.addServer("filesystem", "node", ["./filesystem-server.js"]);await mcpClient.addServer("database", "node", ["./database-server.js"]);await mcpClient.addServer("github", "node", ["./github-server.js"]);
const tools = await mcpClient.discoverAllTools();console.log("Mevcut tool'lar:", Array.from(tools.keys()));// Çıktı: ["filesystem:list_directory", "filesystem:read_file",//          "database:query", "github:create_pr", ...]

Tool namespacing pattern'leri:

  • Server prefix conflict'leri önlüyor (birden fazla server'da get_status tool'u olabilir)
  • Operation'ların clear ownership'ini koruyor
  • Hangi server'ın request'i handle ettiğini belirleyerek debugging'i basitleştiriyor

Production HTTP Deployment

Stdio local development için çalışıyor, ama production sistemler scalability, monitoring ve multi-client desteği için HTTP transport'a ihtiyaç duyuyor.

typescript
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";import express from "express";import crypto from "crypto";
const app = express();
const transport = new StreamableHTTPServerTransport({  enableJsonResponse: true,  sessionIdGenerator: () => crypto.randomUUID(),});
// CORS ve DNS rebinding prevention için allowed origin'lerconst ALLOWED_ORIGINS = [  "http://localhost:3001",  "https://app.example.com",];
function isAllowedOrigin(origin: string | undefined): boolean {  if (!origin) return false;  return ALLOWED_ORIGINS.includes(origin);}
// MCP message endpointapp.post("/mcp/message", async (req, res) => {  // DNS rebinding attack'larını önlemek için origin validate et  const origin = req.headers.origin;  if (origin && !isAllowedOrigin(origin)) {    return res.status(403).json({ error: "Forbidden origin" });  }
  // Session management  const sessionId = req.headers["mcp-session-id"] as string;  console.error(`Session için message işleniyor: ${sessionId}`);
  await transport.handleMessage(req, res);});
// Server-to-client streaming için SSE endpointapp.get("/mcp/events", async (req, res) => {  const origin = req.headers.origin;  if (origin && !isAllowedOrigin(origin)) {    return res.status(403).send("Forbidden");  }
  // Connection drop olduysa last event'ten resume et  const lastEventId = req.headers["last-event-id"] as string;  if (lastEventId) {    console.error(`Event'ten resume ediliyor: ${lastEventId}`);  }
  await transport.handleStream(req, res);});
// Health check endpointapp.get("/health", (req, res) => {  res.json({ status: "healthy", timestamp: new Date().toISOString() });});
// Metrics endpoint (Prometheus formatı)app.get("/metrics", (req, res) => {  // Implementation monitoring setup'a bağlı  res.send("# MCP server metrics\n");});
app.listen(3000, () => {  console.error("MCP server http://localhost:3000 üzerinde dinliyor");});

Production consideration'lar:

  1. Origin validation: Malicious site'ların localhost server'lara bağlanmasını engelleyen DNS rebinding attack'larını önlüyor
  2. Session management: HTTP stateless; session ID'ler request'ler arası conversation context'i track ediyor
  3. SSE resumability: Last-Event-ID header client'ların connection drop sonrası specific event'lerden resume etmesini sağlıyor
  4. Health check'ler: Load balancer health detection ve orchestration platform'ları için essential
  5. Metrics: Latency tracking, error rate'ler ve capacity planning için observability

Güvenlik: Input Validation'dan Ötesi

MCP güvenliği defense in depth gerektiriyor. Tool description'lar security control değil; AI model için hint'ler, prompt injection ile bypass edilebilir.

typescript
// YANLIŞ: Güvenlik için description'a güvenmekserver.registerTool(  "delete_database",  {    title: "Delete Database",    description: "Tüm database'i sil - son derece dikkatli kullan",    inputSchema: {      type: "object",      properties: {        confirm: { type: "boolean" }      },      required: ["confirm"]    }  },  async ({ confirm }) => {    // Description "sadece user explicit request ettiğinde kullan" diyor    // Prompt injection nedeniyle AI yine de invoke edebilir!    await dropDatabase();  });
// DOĞRU: Gerçek safeguard'lar implement etserver.registerTool(  "delete_database",  {    title: "Delete Database",    description: "Proper authorization ile database'i sil",    inputSchema: {      type: "object",      properties: {        confirm: {          type: "string",          enum: ["DELETE_EVERYTHING"],          description: "Exact string DELETE_EVERYTHING olmalı"        },        adminToken: {          type: "string",          description: "Admin authorization token"        }      },      required: ["confirm", "adminToken"]    }  },  async ({ confirm, adminToken }) => {    if (!verifyAdminToken(adminToken)) {      throw new Error("Unauthorized");    }
    // Audit logging    auditLog("delete-database", { token: adminToken });
    await dropDatabase();  });

İmplementasyon gereken security layer'ları:

typescript
// 1. Capability-based access controlclass SecureFileSystem {  private allowedPaths: Set<string>;
  constructor(allowedPaths: string[]) {    this.allowedPaths = new Set(allowedPaths);  }
  async readFile(path: string): Promise<string> {    if (!this.allowedPaths.has(path)) {      throw new Error("Erişim reddedildi");    }    return await readFile(path, "utf-8");  }}
// 2. Compliance için audit loggingfunction auditLog(action: string, params: any, result: any) {  console.error(JSON.stringify({    timestamp: new Date().toISOString(),    action,    params,    result: result.success ? "success" : "failure",    error: result.error,  }));}
// 3. Client başına rate limitingconst rateLimiter = new Map<string, number>();
function checkRateLimit(clientId: string, maxPerSecond: number = 10): boolean {  const now = Date.now();  const key = `${clientId}:${Math.floor(now / 1000)}`;  const count = rateLimiter.get(key) || 0;
  if (count >= maxPerSecond) {    return false;  }
  rateLimiter.set(key, count + 1);
  // Eski entry'leri temizle  for (const [k, v] of rateLimiter.entries()) {    const timestamp = parseInt(k.split(':')[1]);    if (timestamp < Math.floor(now / 1000) - 60) {      rateLimiter.delete(k);    }  }
  return true;}
// 4. Zod'un ötesinde input sanitizationfunction sanitizePath(path: string): string {  // Null byte'ları kaldır, separator'ları normalize et  return path    .replace(/\0/g, '')    .replace(/\\/g, '/')    .replace(/\/+/g, '/');}

Production'da kritik güvenlik problemleri:

  1. Prompt injection: User input'a gömülü malicious instruction'lar tool behavior'ını override edebilir
  2. Tool permission abuse: Proper authorization olmadan excessive privilege'lara sahip tool'lar
  3. Rug pull attack'ları: Installation sonrası behavior değiştiren tool'lar (checksum'ları verify et)
  4. Tool shadowing: Bir server'ın tool'larının diğerinin aynı isimdeki tool'larını override etmesi

Static analysis için Invariant Labs MCP-Scan, runtime monitoring için Akto MCP Security gibi security tool'lar kullan.

Context Window'lar için Optimizasyon

Tool'lardan dönen her byte AI modelinin context window'unu tüketiyor. Conversation başına yüzlerce tool invocation ile inefficient response'lar hızla available token'ları tüketiyor.

typescript
// YANLIŞ: Tüm API response'u döndürmekserver.registerTool("get_user",  {    title: "Get User",    description: "User bilgisini getir",    inputSchema: {      type: "object",      properties: {        id: { type: "string", description: "User ID" }      },      required: ["id"]    }  },  async ({ id }) => {  const user = await api.getUser(id);  return {    content: [{      type: "text",      text: JSON.stringify(user)    }]  };  // 50+ field döndürüyor, sadece 3'ü relevant});
// DOĞRU: Sadece relevant field'ları döndürserver.registerTool("get_user",  {    title: "Get User",    description: "User bilgisini getir",    inputSchema: {      type: "object",      properties: {        id: { type: "string", description: "User ID" }      },      required: ["id"]    }  },  async ({ id }) => {  const user = await api.getUser(id);  return {    content: [{      type: "text",      text: JSON.stringify({        name: user.name,        email: user.email,        status: user.status      })    }]  };});

Token optimization stratejileri:

  1. Schema optimization: Kısa tool description'lar (her kelime sayılıyor)
  2. Progressive disclosure: Detaylı data'yı sadece gerektiğinde yükle
  3. Resource link'ler: Büyük content'i embed etmek yerine reference et
typescript
// Büyük data için resource link kullanserver.registerTool("analyze_repository",  {    title: "Analyze Repository",    description: "Repository'yi dosyalar için tara",    inputSchema: {      type: "object",      properties: {        repo: { type: "string", description: "Repository path" }      },      required: ["repo"]    }  },  async ({ repo }) => {  const files = await scanRepository(repo);
  // Tüm dosya içeriklerini embed etmek yerine (100K+ token),  // resource link'leri döndür  return {    content: [      {        type: "text",        text: `${files.length} dosya bulundu. Detaylar için read_file tool'unu kullan.`      },      ...files.map(f => ({        type: "resource",        resource: { uri: `file://${f}` }      }))    ]  };});

Bir durumda, full API response'lardan selective field extraction'a geçiş context window kullanımını %95 azalttı ve response time'ları 3 kat iyileştirdi.

MCP vs Geleneksel API'ler: Ne Zaman Ne Kullanılmalı

MCP tüm API'lerin replacement'ı değil; specific bir problemi çözüyor. İşte decision framework:

MCP kullan:

  • AI-first application geliştiriyorsan (agent'lar, assistant'lar)
  • Runtime'da dynamic tool discovery gerekiyorsa
  • Birden fazla AI provider destekliyorsan (vendor lock-in'den kaçınmak için)
  • Persistent context ile session-based workflow'lar
  • Hızlı integration development (M×N yerine M+N)

MCP kullanma:

  • Geleneksel client-server application'lar
  • Real-time streaming data (bunun yerine WebSocket kullan)
  • Sub-100ms latency gereksinimleri
  • Agent-to-agent communication (spec'te henüz desteklenmiyor)

Hybrid pattern'ler iyi çalışıyor:

typescript
// Mevcut REST API'yi wrap eden MCP serverclass RESTtoMCPAdapter {  constructor(private baseURL: string, private apiKey: string) {}
  createMCPTools(server: McpServer) {    // OpenAPI spec'ten tool'lar generate et    server.registerTool("create_order",      {        title: "Create Order",        description: "Yeni order oluştur",        inputSchema: {          type: "object",          properties: {            items: {              type: "array",              items: {                type: "object",                properties: {                  id: { type: "string" },                  qty: { type: "number" }                }              }            }          },          required: ["items"]        }      },      async ({ items }) => {        const response = await fetch(`${this.baseURL}/orders`, {          method: 'POST',          headers: { 'Authorization': `Bearer ${this.apiKey}` },          body: JSON.stringify({ items })        });
        const data = await response.json();
        // Context window için response'u optimize et        return {          content: [{            type: "text",            text: JSON.stringify({              orderId: data.id,              status: data.status,              total: data.total            })          }]        };      }    );  }}

Bu pattern mevcut REST API'lerini web/mobile client'lar için korurken AI entegrasyonları için optimize edilmiş MCP interface'leri expose etmeni sağlıyor.

Yaygın Tuzaklar ve Çözümler

MCP ile çalışırken implementation'ları trip eden pattern'ler ortaya çıktı:

1. Protocol İhlalleri

Problem: stdout'a log yazmak JSON-RPC parsing'i bozuyor.

typescript
// YANLIŞconsole.log("Operation başlatılıyor...");
// DOĞRUconsole.error("Operation başlatılıyor...");

2. Stateful stdio vs Stateless HTTP

Problem: In-memory state stdio ile çalışıyor (single process) ama HTTP ile fail oluyor (multiple instance).

typescript
// YANLIŞ - HTTP request'ler arasında kaybolurlet sessionState = {};
// DOĞRU - Redis veya benzerini kullanimport { createClient } from "redis";const redis = createClient();
async function getSession(sessionId: string) {  const data = await redis.get(`session:${sessionId}`);  return data ? JSON.parse(data) : {};}

3. Blocking Long Operation'lar

Problem: Synchronous long-running operation'lar server'ı block ediyor.

typescript
// YANLIŞ - 30 saniye block oluyorserver.registerTool("process_large_file",  {    title: "Process Large File",    description: "Büyük dosyayı işle",    inputSchema: {      type: "object",      properties: {        path: { type: "string", description: "Dosya yolu" }      },      required: ["path"]    }  },  async ({ path }) => {  const result = await processFile(path); // 30 saniye sürüyor  return { content: [{ type: "text", text: result }] };});
// DOĞRU - task pattern kullan (Kasım 2025 itibariyle experimental)const tasks = new Map<string, { status: string; result?: string }>();
server.registerTool("start_processing",  {    title: "Start Processing",    description: "Long-running dosya işleme task'ını başlat",    inputSchema: {      type: "object",      properties: {        path: { type: "string", description: "İşlenecek dosya yolu" }      },      required: ["path"]    }  },  async ({ path }) => {  const taskId = crypto.randomUUID();  tasks.set(taskId, { status: "running" });
  // Background'da işle  processFile(path).then(result => {    tasks.set(taskId, { status: "completed", result });  });
  return {    content: [{      type: "text",      text: `Task ${taskId} başlatıldı. İlerlemeyi izlemek için check_task kullan.`    }]  };});
server.registerTool("check_task",  {    title: "Check Task",    description: "Processing task'ının durumunu kontrol et",    inputSchema: {      type: "object",      properties: {        taskId: { type: "string", description: "Kontrol edilecek Task ID" }      },      required: ["taskId"]    }  },  async ({ taskId }) => {  const task = tasks.get(taskId);  if (!task) {    throw new Error("Task bulunamadı");  }  return { content: [{ type: "text", text: JSON.stringify(task) }] };});

4. Yetersiz Error Handling

Problem: Handle edilmeyen exception'lar tüm server'ı çökertiyor. Try-catch ile graceful error response dönmek gerekiyor. isError: true ile hata durumunu belirt.

Performans Pattern'leri

MCP server'ları optimize etmek geleneksel API optimization'a benzer pattern'leri takip ediyor, token efficiency için additional consideration'larla.

typescript
// Multi-tier cachingconst memCache = new Map<string, any>(); // L1: In-memory (ms latency)const redisClient = createClient(); // L2: Redis (1-5ms latency)
async function getCachedData(key: string) {  // L1'i dene  if (memCache.has(key)) {    return memCache.get(key);  }
  // L2'yi dene  const redisData = await redisClient.get(key);  if (redisData) {    const parsed = JSON.parse(redisData);    memCache.set(key, parsed); // L1'e promote et    return parsed;  }
  // Source'tan fetch et  const dbData = await db.query(key);  await redisClient.setEx(key, 300, JSON.stringify(dbData)); // 5 dk TTL  memCache.set(key, dbData);  return dbData;}

Track edilecek performans metrikleri:

  1. Latency: p50, p95, p99 tool invocation duration
  2. Token efficiency: Conversation başına context window utilization
  3. Error rate'ler: Tool type'a göre success rate
  4. Geographic impact: US-East hosting genelde Anthropic modelleri için %30-40 daha düşük latency sağlıyor

Test'lerde, multi-tier caching p95 latency'yi 200ms'den 15ms'ye düşürdü ve database load'u %70 azalttı.

Gerçek Dünya Entegrasyon Pattern'leri

DevOps Otomasyonu

Birden fazla MCP server'ı combine etmek powerful automation workflow'ları oluşturuyor:

typescript
// Multi-server DevOps workflowserver.registerTool("deploy_feature",  {    title: "Deploy Feature",    description: "Feature branch'i environment'a deploy et",    inputSchema: {      type: "object",      properties: {        branch: { type: "string", description: "Deploy edilecek branch" },        environment: {          type: "string",          enum: ["staging", "production"],          description: "Hedef environment"        }      },      required: ["branch", "environment"]    }  },  async ({ branch, environment }) => {    // 1. GitHub: PR oluştur    const pr = await mcpClient.callTool("github", "create_pr", {      branch,      base: "main",      title: `${branch}'i ${environment}'a deploy et`    });
    // 2. CI: Test'leri çalıştır    const tests = await mcpClient.callTool("ci", "run_tests", {      branch    });
    if (tests.status !== "passed") {      return {        content: [{          type: "text",          text: `Test'ler başarısız: ${tests.failures}`        }],        isError: true      };    }
    // 3. Terraform: Infrastructure'ı apply et    await mcpClient.callTool("terraform", "apply_plan", {      environment,      autoApprove: environment === "staging"    });
    // 4. Slack: Takımı bilgilendir    await mcpClient.callTool("slack", "send_message", {      channel: "#deployments",      text: `${branch} ${environment}'a deploy edildi`    });
    return {      content: [{        type: "text",        text: `${environment}'a başarıyla deploy edildi`      }]    };  });

Bu pattern deployment süresini 45 dakikadan (manual step'ler) 8 dakikaya (AI agent ile otomatik) düşürdü.

Trade-off'lar ve Karar Framework'ü

MCP bir yaşında; hala olgunlaşıyor. Ne zaman mantıklı olduğuna dair öğrendiklerim:

Avantajlar:

  • Standardizasyon M×N entegrasyon problemini M+N'ye düşürüyor
  • Dynamic discovery documentation maintenance yükünü ortadan kaldırıyor
  • Büyüyen pre-built server ecosystem'i (filesystem, GitHub, database'ler)
  • Session management ve resumability protocol'e built-in

Dezavantajlar:

  • Specification hala evolve oluyor (quarterly update'ler)
  • Limited production deployment pattern'leri dokümante edilmiş
  • Security concern'ler dikkatli implementasyon gerektiriyor
  • Agent-to-agent communication için henüz tasarlanmamış

Maliyet consideration'ları:

  • Initial implementation: MCP server başına 2-5 gün vs bespoke integration için 2-3 hafta
  • Infrastructure: stdio ücretsiz, HTTP service başına ~$50-200/ay (3 replica, load balancer)
  • Learning curve: Production-ready expertise için 1-2 hafta

Yatırım birden fazla entegrasyona ihtiyacın olduğunda veya birden fazla AI provider desteklemeyi planladığında karşılığını veriyor. Single-provider, single-tool senaryolar için native function calling daha basit olabilir.

Pratik Sonraki Adımlar

MCP'yi use case'in için değerlendiriyorsan:

  1. Locally stdio ile başla: 2-3 tool ile basit bir server geliştir
  2. MCP Inspector ile test et: AI client'lara bağlanmadan önce protocol compliance'ı verify et
  3. Bir production pattern implement et: Proper error handling ile HTTP transport
  4. Security layer'ları ekle: Input validation, rate limiting, audit logging
  5. Performansı ölç: Latency, token kullanımı ve error rate'leri track et
  6. Hybrid düşün: Rebuild etmek yerine mevcut API'leri MCP adapter'larla wrap et

Official TypeScript SDK (@modelcontextprotocol/sdk) solid foundation'lar sağlıyor. Oradan başla, security guideline'ları takip et ve actual usage pattern'larına göre optimize et.

MCP gerçek bir problemi çözüyor; AI entegrasyonlarını standartlaştırmak; ama magic değil. Herhangi bir production API gibi yaklaş: input'ları validate et, error'ları gracefully handle et, performansı monitor et ve defense-in-depth security implement et.

İlgili Yazılar