0Pricing
AI Engineering Academy · Ders

MCP Güvenliği ve Kimlik Doğrulama

OAuth 2.0 belirteçlerini kullanarak MCP sunucunuza kimlik doğrulama ekleyin, enjeksiyon saldırılarını önlemek için girdileri doğrulayın ve araç izinlerine en az ayrıcalık ilkesini uygulayın.

MCP Güvenliği ve Kimlik Doğrulama, CoddyKit'te ücretsiz bir AI Engineering Academy dersidir. Bu, 4 dersinin 4. dersidir. Aşağıdan dersin tamamını ücretsiz okuyabilir, sonra tarayıcıda yerleşik kod editörü ve 7/24 yapay zeka koçu ile uygulamalı olarak pratik yapabilirsin. Bu, AI Engineering Academy öğrenme yolunun bir parçasıdır ve ilerlemeniz web ve CoddyKit uygulaması arasında senkronize olur. AI Engineering Academy kursu toplamda 4 dersten oluşur.

Bu dersin bazı bölümleri henüz çevrilmemiş olup İngilizce olarak gösterilmektedir.

Why MCP Security Matters

An MCP server is a gateway into your systems. Without proper security, a compromised AI client or malicious prompt could read sensitive data, trigger destructive operations, or exfiltrate information through the tool call channel. Security for MCP servers must be defense in depth: authentication at the transport layer, authorization at the tool level, and input validation on every call.

Local vs. Remote Server Security

The stdio transport (used by Claude Desktop) has inherent security: the server runs as a local process, only accessible to the user who launched it. Network-exposed MCP servers using HTTP/SSE face the full range of web security threats: authentication bypass, injection attacks, and unauthorized access. Security requirements differ dramatically based on deployment mode.

  • Local stdio: Trust the local user; focus on input validation
  • Remote HTTP/SSE: Full authentication, TLS, rate limiting, input sanitization

API Key Authentication for Remote Servers

The simplest authentication for remote MCP servers is API key validation via an HTTP header. Check the Authorization: Bearer <token> header on every incoming request and reject unauthenticated requests with HTTP 401. Store valid API keys in a database with user metadata so you can revoke individual keys.

# For HTTP/SSE MCP servers using FastAPI or similar:
from fastapi import FastAPI, HTTPException, Depends, Header
from typing import Optional
import secrets

app_http = FastAPI()

# In production: store in database with user_id, created_at, last_used
VALID_KEYS = {'sk-mcp-abc123': {'user': 'alice', 'scopes': ['read']},
              'sk-mcp-def456': {'user': 'bob', 'scopes': ['read', 'write']}}

async def verify_api_key(authorization: Optional[str] = Header(None)) -> dict:
    if not authorization or not authorization.startswith('Bearer '):
        raise HTTPException(status_code=401, detail='Missing API key')
    key = authorization.removeprefix('Bearer ')
    if key not in VALID_KEYS:
        raise HTTPException(status_code=401, detail='Invalid API key')
    return VALID_KEYS[key]  # Returns user context

# Use in route handlers:
# @app_http.get('/sse')
# async def sse_endpoint(user=Depends(verify_api_key)):

OAuth 2.0 for Enterprise MCP Servers

For enterprise deployments, use OAuth 2.0 so users authenticate with their corporate identity provider (Okta, Azure AD, Google Workspace). The MCP client obtains an OAuth access token, which it includes in tool call requests. Your server validates the token signature against the identity provider's public keys using python-jose or authlib.

from jose import jwt, JWTError
import httpx

AUTH_DOMAIN = 'your-tenant.auth0.com'
AUDIENCE = 'https://api.your-mcp-server.com'

async def get_jwks():
    async with httpx.AsyncClient() as client:
        resp = await client.get(f'https://{AUTH_DOMAIN}/.well-known/jwks.json')
        return resp.json()

async def verify_oauth_token(token: str) -> dict:
    jwks = await get_jwks()
    try:
        payload = jwt.decode(
            token,
            jwks,
            algorithms=['RS256'],
            audience=AUDIENCE,
            issuer=f'https://{AUTH_DOMAIN}/'
        )
        return payload  # Contains sub (user ID), scope, exp, etc.
    except JWTError as e:
        raise ValueError(f'Invalid token: {e}')

Scope-Based Authorization

Not all MCP tools should be available to all users. Use OAuth scopes or role claims in the JWT token to determine which tools the authenticated user may call. Check authorization at the beginning of every tool execution, before any database or API call is made.

TOOL_REQUIRED_SCOPES = {
    'list_products': ['read:products'],
    'search_products': ['read:products'],
    'create_order': ['write:orders'],
    'delete_order': ['admin:orders']
}

def check_authorization(tool_name: str, token_payload: dict):
    '''Raise ValueError if user lacks required scope for the tool.'''
    required = TOOL_REQUIRED_SCOPES.get(tool_name, [])
    if not required:
        return  # No scope required

    user_scopes = set(token_payload.get('scope', '').split())
    missing = [s for s in required if s not in user_scopes]
    if missing:
        raise ValueError(
            f'Access denied. Tool "{tool_name}" requires scopes: {missing}. '
            f'Your token has: {list(user_scopes)}'
        )

# In call_tool handler:
# check_authorization(name, current_user_token)
# ... then execute the tool

Input Validation and Injection Prevention

All tool inputs are ultimately strings generated by an LLM — treat them as untrusted. Validate every input against expected types and patterns before use. Specifically guard against: SQL injection (use parameterized queries, never string-interpolated SQL), command injection (never pass user input to shell commands), and path traversal (normalize and validate file paths).

import re
from pathlib import Path

BASE_DATA_DIR = Path('/data/mcp-files')

def safe_file_path(user_input: str) -> Path:
    '''Validate and normalize a file path to prevent traversal attacks.'''
    # Remove any path traversal sequences
    clean = re.sub(r'\.\./', '', user_input)
    clean = re.sub(r'\.\.\\\\', '', clean)
    path = (BASE_DATA_DIR / clean).resolve()

    # Ensure the resolved path is still within the allowed base directory
    if not str(path).startswith(str(BASE_DATA_DIR)):
        raise ValueError(f'Path traversal detected: {user_input}')

    return path

def safe_identifier(value: str) -> str:
    '''Validate a database identifier (table/column name).'''
    if not re.match(r'^[a-z_][a-z0-9_]{0,63}$', value, re.IGNORECASE):
        raise ValueError(f'Invalid identifier: {value}')
    return value

Rate Limiting Tool Calls

An LLM agent in a loop could call expensive tools hundreds of times per minute, exhausting your database connections, third-party API quotas, or compute budget. Implement per-user rate limits using a token bucket algorithm in Redis. Reject tool calls that exceed the limit with a descriptive error so the agent knows to wait.

import redis
import time

r = redis.Redis.from_url('redis://localhost:6379')

def check_rate_limit(user_id: str, tool_name: str, limit: int = 60, window: int = 60) -> None:
    '''Allow at most `limit` calls per `window` seconds per user per tool.'''
    key = f'rate:{user_id}:{tool_name}'
    pipe = r.pipeline()
    pipe.incr(key)
    pipe.expire(key, window)
    count, _ = pipe.execute()

    if count > limit:
        retry_after = r.ttl(key)
        raise ValueError(
            f'Rate limit exceeded for {tool_name}. '
            f'Limit: {limit} calls/{window}s. '
            f'Retry after {retry_after} seconds.'
        )

Principle of Least Privilege

Apply the principle of least privilege at every layer of your MCP server. The database user should have SELECT-only on the tables the server needs. The server process should run as a non-root OS user. Tools should request only the permissions they need. API keys should have the minimum scope for their purpose. Each permission you withhold is a potential attack that can't succeed.

-- PostgreSQL: Create a dedicated read-only database user for your MCP server
CREATE ROLE mcp_reader LOGIN PASSWORD 'strong_random_password';

-- Grant SELECT on only the tables the server needs
GRANT SELECT ON products, categories, public_content TO mcp_reader;

-- Explicitly deny access to sensitive tables
REVOKE ALL ON users, api_keys, payment_methods FROM mcp_reader;

-- Never grant: INSERT, UPDATE, DELETE, TRUNCATE, or DDL permissions

TLS and Transport Security

Remote MCP servers must use TLS to protect data in transit. Configure your server to only accept HTTPS connections. In production, use a reverse proxy (nginx, Caddy) to handle TLS termination and keep certificates up to date with automatic renewal (Let's Encrypt via Certbot or Caddy's built-in ACME support).

# Example Caddyfile for TLS-terminating MCP server at a subdomain:
#
# mcp.yourcompany.com {
#     reverse_proxy localhost:8080
#     encode gzip
#     tls internal  # Use Let's Encrypt in production
#     header {
#         Strict-Transport-Security 'max-age=31536000; includeSubDomains'
#         X-Content-Type-Options nosniff
#         X-Frame-Options DENY
#     }
# }

Prompt Injection via MCP Resources

A subtle attack vector: if your MCP server reads content from external sources (web pages, user-uploaded files, untrusted databases) and returns it as a tool result, an attacker could embed adversarial instructions in that content. The model might obey instructions hidden in retrieved data — this is indirect prompt injection. Sanitize retrieved content and never return raw untrusted text directly as tool output.

import re

def sanitize_for_mcp_output(text: str) -> str:
    '''Remove patterns that look like instructions to the LLM.'''
    # Remove common injection patterns
    dangerous_patterns = [
        r'ignore previous instructions',
        r'ignore all prior instructions',
        r'system:',
        r'<\|.*?\|>',  # Special tokens
        r'\[INST\]',
        r'<s>',
    ]
    for pattern in dangerous_patterns:
        text = re.sub(pattern, '[FILTERED]', text, flags=re.IGNORECASE)
    return text[:10000]  # Also cap length to prevent context stuffing

Security Auditing and Monitoring

Log all security-relevant events: authentication successes and failures, rate limit violations, authorization denials, validation errors, and unusual access patterns. Set up alerts for: multiple failed auth attempts (brute force), a single user calling destructive tools rapidly, and any tool call with extremely large inputs. Review audit logs regularly and automate anomaly detection.

Quick Check

Test your understanding of MCP security and authentication concepts.

Lesson Recap

In this lesson you learned: remote MCP servers require OAuth 2.0 or API key authentication on every request, scope-based authorization controls which tools each authenticated user can call, and all tool inputs must be validated to prevent injection attacks and path traversal. This concludes the MCP module — next we explore advanced chunking strategies for high-precision RAG retrieval.

Sıkça Sorulan Sorular

“MCP Güvenliği ve Kimlik Doğrulama” dersi ücretsiz mi?

Evet — “MCP Güvenliği ve Kimlik Doğrulama” dersin tüm metni burada web'de ücretsiz olarak okunabilir. Etkileşimli olarak pratik yapmak (yerleşik kod editörü ve 7/24 yapay zeka koçu) ve AI Engineering Academy kursunun geri kalanını açmak için CoddyKit PRO'ya yükselt. AI Engineering Academy kursu toplamda 4 dersten oluşur.

“MCP Güvenliği ve Kimlik Doğrulama” dersinde ne öğreneceğim?

OAuth 2.0 belirteçlerini kullanarak MCP sunucunuza kimlik doğrulama ekleyin, enjeksiyon saldırılarını önlemek için girdileri doğrulayın ve araç izinlerine en az ayrıcalık ilkesini uygulayın. AI Engineering Academy ile uygulamalı kodu tarayıcıda doğrudan çalıştırarak pratik yaparsın ve 7/24 yapay zeka koçu dersi çalışırken sorularını yanıtlar.

AI Engineering Academy öğrenmeye başlamak için deneyim gerekli mi?

Önceden deneyim gerekmez. CoddyKit'te AI Engineering Academy, başlangıçtan ileri seviyeye kadar yapılandırıldığı için buradan başlayabilir veya başından başlayıp kendi hızında ilerleme yapabilirsin. Bu, 4 dersinin 4. dersidir.

“MCP Güvenliği ve Kimlik Doğrulama” dersi ne kadar sürer?

Çoğu CoddyKit dersi yaklaşık 5–10 dakika sürer. Her biri kısa ve etkileşimli olduğu için sabit ilerleme yaparsın ve web ile uygulama arasında tam olarak bıraktığın yerden devam edebilirsin.

Bu AI Engineering Academy dersinde kod yazıp çalıştırabilir miyim?

Evet. Her AI Engineering Academy dersi yerleşik bir kod editörü içerir, bu sayede tarayıcıda gerçek kod yazıp çalıştırabilir ve anlık yapay zeka geri bildirimi alırsın — yerel kurulum gerekli değildir.

Bu kursun tüm dersleri

  1. MCP Nedir ve Neden Önemlidir
  2. İlk MCP Sunucunuzu Oluşturma
  3. MCP ile Veritabanı Kaynaklarını Kullanıma Sunma
  4. MCP Güvenliği ve Kimlik Doğrulama
← AI Engineering Academy Sayfasına Dön