📚guideintermediate

MCP Security Guide: Implementing Secure MCP Servers

Comprehensive security guide for MCP implementations covering authentication, authorization, data protection, and threat mitigation.

ByMCP Directory Team
Published
⏱️30 minutes
securityauthenticationauthorizationencryptioncompliance

MCP Security Guide: Implementing Secure Model Context Protocol Servers

Security is paramount when implementing Model Context Protocol (MCP) servers, especially in enterprise environments where sensitive data and critical systems are involved. This guide provides comprehensive security practices, implementation patterns, and threat mitigation strategies for MCP deployments.

Table of Contents

  1. Security Architecture Overview
  2. Authentication Mechanisms
  3. Authorization and Access Control
  4. Data Protection and Encryption
  5. Network Security
  6. Input Validation and Sanitization
  7. Audit Logging and Monitoring
  8. Threat Modeling and Mitigation
  9. Compliance Considerations

Security Architecture Overview

Security-First Design Principles

When designing MCP servers, implement security as a foundational layer:

interface SecurityContext {
  identity: UserIdentity;
  permissions: Permission[];
  sessionId: string;
  timestamp: Date;
  source: ConnectionSource;
}

class SecureMCPServer extends Server {
  private securityManager: SecurityManager;
  private auditLogger: AuditLogger;
  
  constructor() {
    super({
      name: "secure-mcp-server",
      version: "1.0.0"
    });
    
    this.securityManager = new SecurityManager();
    this.auditLogger = new AuditLogger();
    this.setupSecurityMiddleware();
  }
  
  private setupSecurityMiddleware() {
    // All requests pass through security validation
    this.addMiddleware(async (request, context, next) => {
      const securityContext = await this.validateSecurity(request, context);
      return await next(request, securityContext);
    });
  }
}

Trust Boundaries

Identify and secure trust boundaries in your MCP architecture:

enum TrustLevel {
  UNTRUSTED = 0,    // External clients
  BASIC = 1,        // Authenticated users
  ELEVATED = 2,     // Privileged operations
  SYSTEM = 3        // Internal system calls
}

class TrustBoundaryManager {
  validateTrustLevel(context: SecurityContext, requiredLevel: TrustLevel): boolean {
    const userTrustLevel = this.calculateTrustLevel(context);
    return userTrustLevel >= requiredLevel;
  }
  
  private calculateTrustLevel(context: SecurityContext): TrustLevel {
    if (context.identity.isSystem) return TrustLevel.SYSTEM;
    if (context.identity.hasElevatedPrivileges) return TrustLevel.ELEVATED;
    if (context.identity.isAuthenticated) return TrustLevel.BASIC;
    return TrustLevel.UNTRUSTED;
  }
}

Authentication Mechanisms

JWT-Based Authentication

Implement robust JWT authentication for MCP servers:

import jwt from 'jsonwebtoken';
import crypto from 'crypto';

class JWTAuthenticator {
  private secretKey: string;
  private publicKey: string;
  private algorithm: string = 'RS256';
  
  constructor(privateKey: string, publicKey: string) {
    this.secretKey = privateKey;
    this.publicKey = publicKey;
  }
  
  async authenticate(token: string): Promise<UserIdentity> {
    try {
      const payload = jwt.verify(token, this.publicKey, {
        algorithms: [this.algorithm],
        issuer: process.env.JWT_ISSUER,
        audience: process.env.JWT_AUDIENCE
      }) as JWTPayload;
      
      // Validate token claims
      if (!this.validateTokenClaims(payload)) {
        throw new Error('Invalid token claims');
      }
      
      return this.createUserIdentity(payload);
    } catch (error) {
      throw new AuthenticationError(`Invalid token: ${error.message}`);
    }
  }
  
  private validateTokenClaims(payload: JWTPayload): boolean {
    // Check token expiration
    if (payload.exp && payload.exp < Date.now() / 1000) {
      return false;
    }
    
    // Validate required claims
    return !!(payload.sub && payload.aud && payload.iss);
  }
  
  private createUserIdentity(payload: JWTPayload): UserIdentity {
    return {
      userId: payload.sub,
      username: payload.username,
      roles: payload.roles || [],
      permissions: payload.permissions || [],
      isAuthenticated: true,
      tokenExpiration: new Date(payload.exp * 1000)
    };
  }
}

OAuth 2.0 Integration

For enterprise environments, integrate with OAuth 2.0 providers:

class OAuth2Authenticator {
  private clientId: string;
  private clientSecret: string;
  private tokenEndpoint: string;
  private userInfoEndpoint: string;
  
  async authenticateWithAuthorizationCode(code: string): Promise<UserIdentity> {
    // Exchange authorization code for access token
    const tokenResponse = await this.exchangeCodeForToken(code);
    
    // Get user information
    const userInfo = await this.getUserInfo(tokenResponse.access_token);
    
    return this.createUserIdentity(userInfo, tokenResponse);
  }
  
  private async exchangeCodeForToken(code: string) {
    const response = await fetch(this.tokenEndpoint, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
        'Authorization': `Basic ${Buffer.from(`${this.clientId}:${this.clientSecret}`).toString('base64')}`
      },
      body: new URLSearchParams({
        grant_type: 'authorization_code',
        code: code,
        redirect_uri: process.env.OAUTH_REDIRECT_URI
      })
    });
    
    if (!response.ok) {
      throw new AuthenticationError('Failed to exchange authorization code');
    }
    
    return await response.json();
  }
  
  private async getUserInfo(accessToken: string) {
    const response = await fetch(this.userInfoEndpoint, {
      headers: {
        'Authorization': `Bearer ${accessToken}`
      }
    });
    
    if (!response.ok) {
      throw new AuthenticationError('Failed to fetch user information');
    }
    
    return await response.json();
  }
}

API Key Authentication

For service-to-service communication:

class APIKeyAuthenticator {
  private keyStore: Map<string, APIKeyInfo> = new Map();
  
  async authenticate(apiKey: string): Promise<UserIdentity> {
    const hashedKey = this.hashApiKey(apiKey);
    const keyInfo = this.keyStore.get(hashedKey);
    
    if (!keyInfo) {
      throw new AuthenticationError('Invalid API key');
    }
    
    if (keyInfo.expiresAt && keyInfo.expiresAt < new Date()) {
      throw new AuthenticationError('API key expired');
    }
    
    if (!keyInfo.isActive) {
      throw new AuthenticationError('API key disabled');
    }
    
    // Update last used timestamp
    keyInfo.lastUsed = new Date();
    
    return {
      userId: keyInfo.serviceAccount,
      username: keyInfo.name,
      roles: keyInfo.roles,
      permissions: keyInfo.permissions,
      isAuthenticated: true,
      authMethod: 'api_key'
    };
  }
  
  private hashApiKey(apiKey: string): string {
    return crypto.createHash('sha256').update(apiKey).digest('hex');
  }
  
  async rotateApiKey(oldKey: string): Promise<string> {
    const newKey = this.generateApiKey();
    const keyInfo = this.keyStore.get(this.hashApiKey(oldKey));
    
    if (keyInfo) {
      this.keyStore.delete(this.hashApiKey(oldKey));
      this.keyStore.set(this.hashApiKey(newKey), {
        ...keyInfo,
        createdAt: new Date(),
        lastRotated: new Date()
      });
    }
    
    return newKey;
  }
  
  private generateApiKey(): string {
    return crypto.randomBytes(32).toString('hex');
  }
}

Authorization and Access Control

Role-Based Access Control (RBAC)

Implement comprehensive RBAC for MCP operations:

interface Role {
  name: string;
  permissions: Permission[];
  description: string;
}

interface Permission {
  resource: string;
  action: string;
  conditions?: PermissionCondition[];
}

class RBACAuthorizer {
  private roles: Map<string, Role> = new Map();
  private userRoles: Map<string, string[]> = new Map();
  
  async authorize(
    identity: UserIdentity,
    resource: string,
    action: string,
    context?: any
  ): Promise<AuthorizationResult> {
    const userRoles = this.getUserRoles(identity.userId);
    
    for (const roleName of userRoles) {
      const role = this.roles.get(roleName);
      if (role && await this.checkRolePermission(role, resource, action, context)) {
        return {
          allowed: true,
          reason: `Authorized via role: ${roleName}`
        };
      }
    }
    
    return {
      allowed: false,
      reason: 'Insufficient permissions'
    };
  }
  
  private async checkRolePermission(
    role: Role,
    resource: string,
    action: string,
    context?: any
  ): Promise<boolean> {
    for (const permission of role.permissions) {
      if (this.matchesPermission(permission, resource, action)) {
        if (permission.conditions) {
          return await this.evaluateConditions(permission.conditions, context);
        }
        return true;
      }
    }
    return false;
  }
  
  private matchesPermission(permission: Permission, resource: string, action: string): boolean {
    const resourceMatch = permission.resource === '*' || 
                         permission.resource === resource ||
                         this.matchesPattern(permission.resource, resource);
    
    const actionMatch = permission.action === '*' || 
                       permission.action === action ||
                       this.matchesPattern(permission.action, action);
    
    return resourceMatch && actionMatch;
  }
  
  private matchesPattern(pattern: string, value: string): boolean {
    const regex = new RegExp(pattern.replace(/\*/g, '.*'));
    return regex.test(value);
  }
  
  private async evaluateConditions(
    conditions: PermissionCondition[],
    context: any
  ): Promise<boolean> {
    for (const condition of conditions) {
      if (!await this.evaluateCondition(condition, context)) {
        return false;
      }
    }
    return true;
  }
}

Attribute-Based Access Control (ABAC)

For more fine-grained control:

interface AttributeCondition {
  attribute: string;
  operator: 'equals' | 'contains' | 'greater_than' | 'less_than' | 'in';
  value: any;
}

class ABACAuthorizer {
  async authorize(
    subject: UserIdentity,
    resource: any,
    action: string,
    environment?: any
  ): Promise<AuthorizationResult> {
    const policy = await this.findApplicablePolicy(subject, resource, action);
    
    if (!policy) {
      return { allowed: false, reason: 'No applicable policy found' };
    }
    
    const context = {
      subject,
      resource,
      action,
      environment: environment || {},
      time: new Date()
    };
    
    const result = await this.evaluatePolicy(policy, context);
    return result;
  }
  
  private async evaluatePolicy(policy: ABACPolicy, context: any): Promise<AuthorizationResult> {
    // Evaluate all conditions in the policy
    for (const rule of policy.rules) {
      const ruleResult = await this.evaluateRule(rule, context);
      
      if (rule.effect === 'DENY' && ruleResult) {
        return { allowed: false, reason: `Denied by rule: ${rule.name}` };
      }
      
      if (rule.effect === 'ALLOW' && ruleResult) {
        return { allowed: true, reason: `Allowed by rule: ${rule.name}` };
      }
    }
    
    return { allowed: false, reason: 'No matching allow rule' };
  }
  
  private async evaluateRule(rule: ABACRule, context: any): Promise<boolean> {
    for (const condition of rule.conditions) {
      if (!await this.evaluateAttributeCondition(condition, context)) {
        return false;
      }
    }
    return true;
  }
  
  private async evaluateAttributeCondition(
    condition: AttributeCondition,
    context: any
  ): Promise<boolean> {
    const attributeValue = this.getAttributeValue(condition.attribute, context);
    
    switch (condition.operator) {
      case 'equals':
        return attributeValue === condition.value;
      case 'contains':
        return Array.isArray(attributeValue) && attributeValue.includes(condition.value);
      case 'greater_than':
        return attributeValue > condition.value;
      case 'less_than':
        return attributeValue < condition.value;
      case 'in':
        return Array.isArray(condition.value) && condition.value.includes(attributeValue);
      default:
        return false;
    }
  }
}

Data Protection and Encryption

Data Encryption at Rest

Implement encryption for sensitive data:

import crypto from 'crypto';

class DataEncryption {
  private algorithm: string = 'aes-256-gcm';
  private keyDerivationSalt: Buffer;
  
  constructor(private masterKey: string) {
    this.keyDerivationSalt = crypto.randomBytes(32);
  }
  
  encrypt(data: string, context?: string): EncryptedData {
    const iv = crypto.randomBytes(16);
    const salt = crypto.randomBytes(32);
    
    // Derive encryption key
    const key = crypto.pbkdf2Sync(this.masterKey, salt, 100000, 32, 'sha256');
    
    const cipher = crypto.createCipher(this.algorithm, key);
    cipher.setAAD(Buffer.from(context || ''));
    
    let encrypted = cipher.update(data, 'utf8', 'hex');
    encrypted += cipher.final('hex');
    
    const authTag = cipher.getAuthTag();
    
    return {
      encryptedData: encrypted,
      iv: iv.toString('hex'),
      salt: salt.toString('hex'),
      authTag: authTag.toString('hex'),
      algorithm: this.algorithm
    };
  }
  
  decrypt(encryptedData: EncryptedData, context?: string): string {
    const iv = Buffer.from(encryptedData.iv, 'hex');
    const salt = Buffer.from(encryptedData.salt, 'hex');
    const authTag = Buffer.from(encryptedData.authTag, 'hex');
    
    // Derive decryption key
    const key = crypto.pbkdf2Sync(this.masterKey, salt, 100000, 32, 'sha256');
    
    const decipher = crypto.createDecipher(encryptedData.algorithm, key);
    decipher.setAAD(Buffer.from(context || ''));
    decipher.setAuthTag(authTag);
    
    let decrypted = decipher.update(encryptedData.encryptedData, 'hex', 'utf8');
    decrypted += decipher.final('utf8');
    
    return decrypted;
  }
}

Data Encryption in Transit

Ensure all communications are encrypted:

import https from 'https';
import fs from 'fs';

class SecureTransport {
  private tlsOptions: https.ServerOptions;
  
  constructor() {
    this.tlsOptions = {
      key: fs.readFileSync('path/to/private-key.pem'),
      cert: fs.readFileSync('path/to/certificate.pem'),
      ca: fs.readFileSync('path/to/ca-bundle.pem'),
      
      // Security configurations
      secureProtocol: 'TLSv1_3_method',
      ciphers: [
        'ECDHE-RSA-AES128-GCM-SHA256',
        'ECDHE-RSA-AES256-GCM-SHA384',
        'ECDHE-RSA-AES128-SHA256',
        'ECDHE-RSA-AES256-SHA384'
      ].join(':'),
      
      honorCipherOrder: true,
      requestCert: true,
      rejectUnauthorized: true
    };
  }
  
  createSecureServer(app: any): https.Server {
    return https.createServer(this.tlsOptions, app);
  }
  
  validateClientCertificate(cert: any): boolean {
    // Implement certificate validation logic
    if (!cert || !cert.subject) {
      return false;
    }
    
    // Check certificate expiration
    const now = new Date();
    const notBefore = new Date(cert.valid_from);
    const notAfter = new Date(cert.valid_to);
    
    if (now < notBefore || now > notAfter) {
      return false;
    }
    
    // Additional validation logic
    return this.validateCertificateChain(cert);
  }
}

Network Security

Rate Limiting and DDoS Protection

Implement comprehensive rate limiting:

class RateLimiter {
  private limits: Map<string, RateLimit> = new Map();
  private attempts: Map<string, AttemptRecord[]> = new Map();
  
  async checkLimit(
    identifier: string,
    limitType: string,
    customLimit?: RateLimit
  ): Promise<RateLimitResult> {
    const limit = customLimit || this.limits.get(limitType);
    if (!limit) {
      return { allowed: true, remainingRequests: Infinity, resetTime: new Date() };
    }
    
    const now = new Date();
    const windowStart = new Date(now.getTime() - limit.windowMs);
    
    // Clean old attempts
    const attempts = this.attempts.get(identifier) || [];
    const validAttempts = attempts.filter(attempt => attempt.timestamp > windowStart);
    
    if (validAttempts.length >= limit.maxRequests) {
      return {
        allowed: false,
        remainingRequests: 0,
        resetTime: new Date(validAttempts[0].timestamp.getTime() + limit.windowMs),
        retryAfter: Math.ceil((validAttempts[0].timestamp.getTime() + limit.windowMs - now.getTime()) / 1000)
      };
    }
    
    // Record this attempt
    validAttempts.push({ timestamp: now, success: true });
    this.attempts.set(identifier, validAttempts);
    
    return {
      allowed: true,
      remainingRequests: limit.maxRequests - validAttempts.length,
      resetTime: new Date(windowStart.getTime() + limit.windowMs)
    };
  }
  
  async recordFailedAttempt(identifier: string, reason: string): Promise<void> {
    const attempts = this.attempts.get(identifier) || [];
    attempts.push({
      timestamp: new Date(),
      success: false,
      reason: reason
    });
    
    this.attempts.set(identifier, attempts);
    
    // Check for suspicious patterns
    await this.detectSuspiciousActivity(identifier, attempts);
  }
  
  private async detectSuspiciousActivity(
    identifier: string,
    attempts: AttemptRecord[]
  ): Promise<void> {
    const recentFailures = attempts.filter(
      attempt => !attempt.success && 
      attempt.timestamp > new Date(Date.now() - 300000) // Last 5 minutes
    );
    
    if (recentFailures.length > 10) {
      await this.triggerSecurityAlert({
        type: 'SUSPICIOUS_ACTIVITY',
        identifier,
        details: `${recentFailures.length} failed attempts in 5 minutes`,
        severity: 'HIGH'
      });
    }
  }
}

Firewall and IP Filtering

class IPFilter {
  private allowedIPs: Set<string> = new Set();
  private blockedIPs: Set<string> = new Set();
  private ipRanges: IPRange[] = [];
  
  isAllowed(clientIP: string): boolean {
    // Check blocked IPs first
    if (this.blockedIPs.has(clientIP)) {
      return false;
    }
    
    // Check explicitly allowed IPs
    if (this.allowedIPs.has(clientIP)) {
      return true;
    }
    
    // Check IP ranges
    return this.ipRanges.some(range => this.isIPInRange(clientIP, range));
  }
  
  private isIPInRange(ip: string, range: IPRange): boolean {
    const ipNum = this.ipToNumber(ip);
    const rangeStart = this.ipToNumber(range.start);
    const rangeEnd = this.ipToNumber(range.end);
    
    return ipNum >= rangeStart && ipNum <= rangeEnd;
  }
  
  private ipToNumber(ip: string): number {
    return ip.split('.').reduce((acc, octet) => acc * 256 + parseInt(octet), 0);
  }
  
  async blockIP(ip: string, reason: string, duration?: number): Promise<void> {
    this.blockedIPs.add(ip);
    
    await this.auditLogger.log({
      action: 'IP_BLOCKED',
      details: { ip, reason, duration },
      timestamp: new Date()
    });
    
    if (duration) {
      setTimeout(() => {
        this.blockedIPs.delete(ip);
      }, duration);
    }
  }
}

Input Validation and Sanitization

Schema-Based Validation

Use strict schema validation for all inputs:

import { z } from 'zod';

class InputValidator {
  private schemas: Map<string, z.ZodSchema> = new Map();
  
  constructor() {
    this.setupSchemas();
  }
  
  private setupSchemas() {
    // Tool call validation
    this.schemas.set('tool_call', z.object({
      name: z.string().min(1).max(100).regex(/^[a-zA-Z_][a-zA-Z0-9_]*$/),
      arguments: z.record(z.any()).optional()
    }));
    
    // Resource URI validation
    this.schemas.set('resource_uri', z.string().url().max(2048));
    
    // User input validation
    this.schemas.set('user_input', z.string().max(10000));
  }
  
  validate<T>(schemaName: string, input: unknown): T {
    const schema = this.schemas.get(schemaName);
    if (!schema) {
      throw new ValidationError(`Unknown schema: ${schemaName}`);
    }
    
    try {
      return schema.parse(input) as T;
    } catch (error) {
      if (error instanceof z.ZodError) {
        throw new ValidationError(`Validation failed: ${error.message}`);
      }
      throw error;
    }
  }
  
  sanitizeInput(input: string): string {
    // Remove potentially dangerous characters
    return input
      .replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '')
      .replace(/javascript:/gi, '')
      .replace(/on\w+\s*=/gi, '')
      .trim();
  }
  
  validateSQL(query: string): boolean {
    const dangerousPatterns = [
      /drop\s+table/i,
      /delete\s+from/i,
      /update\s+\w+\s+set/i,
      /insert\s+into/i,
      /create\s+table/i,
      /alter\s+table/i,
      /truncate\s+table/i,
      /exec\s*\(/i,
      /xp_/i,
      /sp_/i
    ];
    
    return !dangerousPatterns.some(pattern => pattern.test(query));
  }
}

Content Security and Sanitization

class ContentSanitizer {
  private allowedTags: Set<string> = new Set(['p', 'br', 'strong', 'em', 'ul', 'ol', 'li']);
  private allowedAttributes: Map<string, string[]> = new Map([
    ['a', ['href', 'title']],
    ['img', ['src', 'alt', 'width', 'height']]
  ]);
  
  sanitizeHTML(html: string): string {
    // Use a library like DOMPurify in production
    return this.removeDisallowedTags(html);
  }
  
  private removeDisallowedTags(html: string): string {
    // Basic implementation - use proper HTML sanitization library
    return html.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '');
  }
  
  sanitizeFilename(filename: string): string {
    return filename
      .replace(/[^a-zA-Z0-9._-]/g, '_')
      .replace(/\.+/g, '.')
      .substring(0, 255);
  }
  
  validateFileType(filename: string, allowedTypes: string[]): boolean {
    const extension = filename.split('.').pop()?.toLowerCase();
    return extension ? allowedTypes.includes(extension) : false;
  }
}

Audit Logging and Monitoring

Comprehensive Audit Logging

interface AuditEvent {
  eventId: string;
  timestamp: Date;
  userId?: string;
  action: string;
  resource: string;
  result: 'SUCCESS' | 'FAILURE' | 'BLOCKED';
  details: any;
  clientIP: string;
  userAgent?: string;
  sessionId?: string;
}

class AuditLogger {
  private logStorage: AuditStorage;
  private alertManager: AlertManager;
  
  async logEvent(event: Partial<AuditEvent>): Promise<void> {
    const auditEvent: AuditEvent = {
      eventId: crypto.randomUUID(),
      timestamp: new Date(),
      ...event
    } as AuditEvent;
    
    // Store the event
    await this.logStorage.store(auditEvent);
    
    // Check for security alerts
    await this.checkForSecurityAlerts(auditEvent);
  }
  
  async logAuthentication(
    userId: string,
    result: 'SUCCESS' | 'FAILURE',
    method: string,
    clientIP: string
  ): Promise<void> {
    await this.logEvent({
      userId,
      action: 'AUTHENTICATION',
      resource: 'auth',
      result,
      details: { method },
      clientIP
    });
  }
  
  async logAuthorization(
    userId: string,
    resource: string,
    action: string,
    result: 'SUCCESS' | 'BLOCKED',
    reason?: string
  ): Promise<void> {
    await this.logEvent({
      userId,
      action: 'AUTHORIZATION',
      resource: `${resource}:${action}`,
      result,
      details: { reason }
    });
  }
  
  async logDataAccess(
    userId: string,
    resource: string,
    operation: string,
    result: 'SUCCESS' | 'FAILURE'
  ): Promise<void> {
    await this.logEvent({
      userId,
      action: 'DATA_ACCESS',
      resource,
      result,
      details: { operation }
    });
  }
  
  private async checkForSecurityAlerts(event: AuditEvent): Promise<void> {
    // Check for multiple failed authentication attempts
    if (event.action === 'AUTHENTICATION' && event.result === 'FAILURE') {
      const recentFailures = await this.logStorage.getRecentFailures(
        event.clientIP,
        300000 // 5 minutes
      );
      
      if (recentFailures.length > 5) {
        await this.alertManager.triggerAlert({
          type: 'BRUTE_FORCE_ATTEMPT',
          severity: 'HIGH',
          details: {
            clientIP: event.clientIP,
            failureCount: recentFailures.length
          }
        });
      }
    }
    
    // Check for privilege escalation attempts
    if (event.result === 'BLOCKED' && event.action === 'AUTHORIZATION') {
      await this.alertManager.triggerAlert({
        type: 'PRIVILEGE_ESCALATION_ATTEMPT',
        severity: 'MEDIUM',
        details: {
          userId: event.userId,
          resource: event.resource,
          clientIP: event.clientIP
        }
      });
    }
  }
}

Security Monitoring and Alerting

class SecurityMonitor {
  private alertRules: SecurityRule[] = [];
  private notificationChannels: NotificationChannel[] = [];
  
  async monitorEvents(events: AuditEvent[]): Promise<void> {
    for (const event of events) {
      await this.evaluateRules(event);
    }
  }
  
  private async evaluateRules(event: AuditEvent): Promise<void> {
    for (const rule of this.alertRules) {
      if (await this.ruleMatches(rule, event)) {
        await this.triggerAlert(rule, event);
      }
    }
  }
  
  private async ruleMatches(rule: SecurityRule, event: AuditEvent): Promise<boolean> {
    // Evaluate rule conditions against the event
    for (const condition of rule.conditions) {
      if (!this.evaluateCondition(condition, event)) {
        return false;
      }
    }
    return true;
  }
  
  private async triggerAlert(rule: SecurityRule, event: AuditEvent): Promise<void> {
    const alert: SecurityAlert = {
      id: crypto.randomUUID(),
      ruleId: rule.id,
      severity: rule.severity,
      timestamp: new Date(),
      event,
      message: rule.message
    };
    
    // Send notifications
    for (const channel of this.notificationChannels) {
      await channel.sendAlert(alert);
    }
    
    // Store alert for analysis
    await this.storeAlert(alert);
  }
}

Threat Modeling and Mitigation

Common MCP Security Threats

  1. Data Exposure: Unauthorized access to sensitive resources
  2. Code Injection: Malicious code execution through tool calls
  3. Privilege Escalation: Unauthorized access to higher-privilege operations
  4. Man-in-the-Middle: Interception of communication
  5. Denial of Service: Resource exhaustion attacks

Threat Mitigation Strategies

class ThreatMitigator {
  // Prevent data exposure
  async preventDataExposure(request: any, identity: UserIdentity): Promise<void> {
    // Implement data classification and access controls
    const dataClassification = await this.classifyResource(request.resource);
    
    if (dataClassification.level === 'CONFIDENTIAL' && !identity.hasHighClearance) {
      throw new SecurityError('Access denied: insufficient clearance level');
    }
    
    // Implement data masking for sensitive fields
    if (dataClassification.containsPII) {
      await this.maskSensitiveData(request.resource);
    }
  }
  
  // Prevent code injection
  async preventCodeInjection(toolCall: any): Promise<void> {
    const dangerousPatterns = [
      /eval\s*\(/i,
      /exec\s*\(/i,
      /system\s*\(/i,
      /shell_exec\s*\(/i,
      /__import__\s*\(/i,
      /require\s*\(/i
    ];
    
    const inputString = JSON.stringify(toolCall.arguments);
    
    for (const pattern of dangerousPatterns) {
      if (pattern.test(inputString)) {
        throw new SecurityError('Potential code injection detected');
      }
    }
  }
  
  // Implement resource quotas
  async enforceResourceQuotas(identity: UserIdentity, operation: string): Promise<void> {
    const quota = await this.getUserQuota(identity.userId);
    const currentUsage = await this.getCurrentUsage(identity.userId);
    
    if (currentUsage.requests >= quota.maxRequests) {
      throw new SecurityError('Request quota exceeded');
    }
    
    if (currentUsage.dataTransfer >= quota.maxDataTransfer) {
      throw new SecurityError('Data transfer quota exceeded');
    }
  }
}

Compliance Considerations

GDPR Compliance

class GDPRCompliance {
  async handleDataRequest(request: DataRequest): Promise<any> {
    switch (request.type) {
      case 'ACCESS':
        return await this.handleAccessRequest(request);
      case 'DELETION':
        return await this.handleDeletionRequest(request);
      case 'PORTABILITY':
        return await this.handlePortabilityRequest(request);
      case 'RECTIFICATION':
        return await this.handleRectificationRequest(request);
      default:
        throw new Error('Unknown request type');
    }
  }
  
  private async handleDeletionRequest(request: DataRequest): Promise<void> {
    // Identify all data related to the user
    const userData = await this.findUserData(request.userId);
    
    // Delete user data while preserving audit trails
    for (const dataItem of userData) {
      if (dataItem.canBeDeleted) {
        await this.deleteData(dataItem);
      } else {
        await this.anonymizeData(dataItem);
      }
    }
    
    // Log the deletion for compliance
    await this.auditLogger.logEvent({
      action: 'GDPR_DELETION',
      userId: request.userId,
      result: 'SUCCESS',
      details: { requestId: request.id }
    });
  }
}

SOC 2 Compliance

class SOC2Compliance {
  async generateAccessReport(): Promise<AccessReport> {
    const accessEvents = await this.auditLogger.getAccessEvents(
      new Date(Date.now() - 86400000 * 30) // Last 30 days
    );
    
    return {
      totalAccesses: accessEvents.length,
      uniqueUsers: new Set(accessEvents.map(e => e.userId)).size,
      failedAttempts: accessEvents.filter(e => e.result === 'FAILURE').length,
      unauthorizedAttempts: accessEvents.filter(e => e.result === 'BLOCKED').length,
      topResources: this.getTopAccessedResources(accessEvents)
    };
  }
  
  async validateSecurityControls(): Promise<ControlValidationResult[]> {
    const controls = [
      { name: 'Encryption at Rest', validator: () => this.validateEncryptionAtRest() },
      { name: 'Access Controls', validator: () => this.validateAccessControls() },
      { name: 'Audit Logging', validator: () => this.validateAuditLogging() },
      { name: 'Network Security', validator: () => this.validateNetworkSecurity() }
    ];
    
    const results = [];
    for (const control of controls) {
      results.push({
        controlName: control.name,
        status: await control.validator(),
        timestamp: new Date()
      });
    }
    
    return results;
  }
}

Security Best Practices Summary

  1. Defense in Depth: Implement multiple layers of security controls
  2. Principle of Least Privilege: Grant minimum necessary permissions
  3. Zero Trust Architecture: Verify every request regardless of source
  4. Regular Security Assessments: Conduct periodic security reviews and penetration testing
  5. Incident Response Plan: Have a documented plan for security incidents
  6. Security Training: Ensure all developers understand security best practices
  7. Continuous Monitoring: Implement real-time security monitoring and alerting

Next Steps

This comprehensive security guide provides the foundation for building secure, compliant MCP servers that protect sensitive data and maintain user trust while enabling powerful AI integrations.