Chapter 9: Security and Access Control

Haiyue
57min

Chapter 9: Security and Access Control

Learning Objectives

  1. Understand the MCP security model and threat protection
  2. Implement authentication and authorization mechanisms
  3. Master resource access control
  4. Learn input validation and data sanitization
  5. Implement security auditing and monitoring

9.1 MCP Security Model and Threat Analysis

9.1.1 Security Threat Model

The main security threats faced by the MCP Server:

// src/security/ThreatModel.ts
export enum ThreatCategory {
  AUTHENTICATION = 'authentication',
  AUTHORIZATION = 'authorization',
  INPUT_VALIDATION = 'input_validation',
  DATA_EXPOSURE = 'data_exposure',
  RESOURCE_ACCESS = 'resource_access',
  DENIAL_OF_SERVICE = 'denial_of_service',
  CODE_INJECTION = 'code_injection',
  PRIVILEGE_ESCALATION = 'privilege_escalation',
}

export interface SecurityThreat {
  id: string;
  category: ThreatCategory;
  severity: 'low' | 'medium' | 'high' | 'critical';
  description: string;
  impact: string;
  mitigations: string[];
  examples?: string[];
}

export const COMMON_THREATS: SecurityThreat[] = [
  {
    id: 'UNAUTH_ACCESS',
    category: ThreatCategory.AUTHENTICATION,
    severity: 'critical',
    description: 'Unauthorized access',
    impact: 'Malicious users may gain unauthorized access to system resources',
    mitigations: [
      'Implement mandatory authentication',
      'Use secure authentication protocols',
      'Implement session management',
      'Enable account lockout mechanisms'
    ],
    examples: [
      'Direct access to sensitive tools without verification',
      'Bypassing authentication mechanisms to access resources'
    ]
  },
  {
    id: 'PRIVILEGE_ESC',
    category: ThreatCategory.PRIVILEGE_ESCALATION,
    severity: 'high',
    description: 'Privilege escalation attack',
    impact: 'Low-privilege users gain high-privilege operation capabilities',
    mitigations: [
      'Implement the principle of least privilege',
      'Regularly audit permission assignments',
      'Use role-based access control',
      'Implement permission boundary checks'
    ]
  },
  {
    id: 'INJECTION_ATTACK',
    category: ThreatCategory.CODE_INJECTION,
    severity: 'critical',
    description: 'Code injection attack',
    impact: 'Malicious code execution can lead to complete system control',
    mitigations: [
      'Strict input validation',
      'Use parameterized queries',
      'Implement input sanitization',
      'Code execution sandboxing'
    ],
    examples: [
      'SQL injection attack',
      'Command injection attack',
      'Script injection attack'
    ]
  },
  {
    id: 'DATA_LEAK',
    category: ThreatCategory.DATA_EXPOSURE,
    severity: 'high',
    description: 'Sensitive data leakage',
    impact: 'Confidential information may be accessed or leaked without authorization',
    mitigations: [
      'Data classification and tagging',
      'Access control policies',
      'Data encryption at rest',
      'Audit log monitoring'
    ]
  },
  {
    id: 'DOS_ATTACK',
    category: ThreatCategory.DENIAL_OF_SERVICE,
    severity: 'medium',
    description: 'Denial of service attack',
    impact: 'Service availability is affected',
    mitigations: [
      'Request rate limiting',
      'Resource usage monitoring',
      'Request size limiting',
      'Connection count limiting'
    ]
  }
];

export class SecurityAssessment {
  private threats: Map<string, SecurityThreat> = new Map();
  private assessmentResults: Map<string, SecurityAssessmentResult> = new Map();
  
  constructor() {
    COMMON_THREATS.forEach(threat => {
      this.threats.set(threat.id, threat);
    });
  }
  
  async assessThreat(threatId: string, context: any): Promise<SecurityAssessmentResult> {
    const threat = this.threats.get(threatId);
    if (!threat) {
      throw new Error(`Unknown threat: ${threatId}`);
    }
    
    const result: SecurityAssessmentResult = {
      threatId,
      assessedAt: new Date(),
      riskLevel: this.calculateRiskLevel(threat, context),
      mitigationsApplied: [],
      recommendations: [...threat.mitigations],
      context,
    };
    
    this.assessmentResults.set(threatId, result);
    return result;
  }
  
  private calculateRiskLevel(threat: SecurityThreat, context: any): 'low' | 'medium' | 'high' | 'critical' {
    // Simplified risk calculation logic
    let riskLevel = threat.severity;
    
    // Adjust risk level based on context
    if (context.hasPublicAccess && riskLevel !== 'critical') {
      riskLevel = this.increaseSeverity(riskLevel);
    }
    
    if (context.hasPrivilegedOperations && riskLevel !== 'critical') {
      riskLevel = this.increaseSeverity(riskLevel);
    }
    
    return riskLevel;
  }
  
  private increaseSeverity(current: string): 'low' | 'medium' | 'high' | 'critical' {
    switch (current) {
      case 'low': return 'medium';
      case 'medium': return 'high';
      case 'high': return 'critical';
      default: return 'critical';
    }
  }
}

export interface SecurityAssessmentResult {
  threatId: string;
  assessedAt: Date;
  riskLevel: 'low' | 'medium' | 'high' | 'critical';
  mitigationsApplied: string[];
  recommendations: string[];
  context: any;
}

9.1.2 Security Configuration and Policies

// src/security/SecurityConfig.ts
export interface SecurityConfig {
  authentication: {
    required: boolean;
    methods: AuthMethod[];
    sessionTimeout: number; // milliseconds
    maxLoginAttempts: number;
    lockoutDuration: number; // milliseconds
  };
  
  authorization: {
    model: 'rbac' | 'abac' | 'none';
    defaultRole?: string;
    requireExplicitPermissions: boolean;
  };
  
  inputValidation: {
    enableStrictValidation: boolean;
    maxPayloadSize: number; // bytes
    allowedContentTypes: string[];
    sanitizeInputs: boolean;
  };
  
  rateLimiting: {
    enabled: boolean;
    windowMs: number;
    maxRequests: number;
    skipSuccessfulRequests?: boolean;
  };
  
  encryption: {
    algorithm: string;
    keySize: number;
    encryptSensitiveData: boolean;
  };
  
  audit: {
    enabled: boolean;
    logLevel: 'minimal' | 'standard' | 'detailed';
    retentionDays: number;
  };
  
  cors: {
    enabled: boolean;
    allowedOrigins: string[];
    allowedMethods: string[];
    allowedHeaders: string[];
    credentials: boolean;
  };
}

export const DEFAULT_SECURITY_CONFIG: SecurityConfig = {
  authentication: {
    required: true,
    methods: [AuthMethod.API_KEY],
    sessionTimeout: 3600000, // 1 hour
    maxLoginAttempts: 5,
    lockoutDuration: 900000, // 15 minutes
  },
  authorization: {
    model: 'rbac',
    defaultRole: 'user',
    requireExplicitPermissions: true,
  },
  inputValidation: {
    enableStrictValidation: true,
    maxPayloadSize: 1024 * 1024, // 1MB
    allowedContentTypes: ['application/json'],
    sanitizeInputs: true,
  },
  rateLimiting: {
    enabled: true,
    windowMs: 60000, // 1 minute
    maxRequests: 100,
    skipSuccessfulRequests: false,
  },
  encryption: {
    algorithm: 'aes-256-gcm',
    keySize: 32,
    encryptSensitiveData: true,
  },
  audit: {
    enabled: true,
    logLevel: 'standard',
    retentionDays: 30,
  },
  cors: {
    enabled: false,
    allowedOrigins: [],
    allowedMethods: ['POST'],
    allowedHeaders: ['Content-Type', 'Authorization'],
    credentials: false,
  },
};

export enum AuthMethod {
  API_KEY = 'api_key',
  JWT = 'jwt',
  OAUTH2 = 'oauth2',
  BASIC = 'basic',
}

9.2 Authentication System

9.2.1 Authentication Interface and Implementation

// src/auth/Authentication.ts
export interface AuthenticationProvider {
  name: string;
  authenticate(credentials: any): Promise<AuthenticationResult>;
  validateToken(token: string): Promise<TokenValidationResult>;
  refreshToken?(refreshToken: string): Promise<RefreshTokenResult>;
}

export interface AuthenticationResult {
  success: boolean;
  user?: UserInfo;
  token?: string;
  refreshToken?: string;
  expiresAt?: Date;
  error?: string;
}

export interface TokenValidationResult {
  valid: boolean;
  user?: UserInfo;
  expiresAt?: Date;
  error?: string;
}

export interface RefreshTokenResult {
  success: boolean;
  token?: string;
  refreshToken?: string;
  expiresAt?: Date;
  error?: string;
}

export interface UserInfo {
  id: string;
  username: string;
  email?: string;
  roles: string[];
  permissions: string[];
  metadata?: Record<string, any>;
}

// API Key Authentication Provider
export class ApiKeyAuthProvider implements AuthenticationProvider {
  name = 'api_key';
  private apiKeys = new Map<string, UserInfo>();
  private hashedKeys = new Map<string, string>(); // hashed -> original
  
  constructor(private secretKey: string) {}
  
  async authenticate(credentials: { apiKey: string }): Promise<AuthenticationResult> {
    if (!credentials.apiKey) {
      return {
        success: false,
        error: 'API key is required',
      };
    }
    
    const hashedKey = await this.hashApiKey(credentials.apiKey);
    const user = this.apiKeys.get(hashedKey);
    
    if (!user) {
      return {
        success: false,
        error: 'Invalid API key',
      };
    }
    
    return {
      success: true,
      user,
      token: credentials.apiKey, // API key serves as token
    };
  }
  
  async validateToken(token: string): Promise<TokenValidationResult> {
    const hashedKey = await this.hashApiKey(token);
    const user = this.apiKeys.get(hashedKey);
    
    return {
      valid: !!user,
      user,
      error: user ? undefined : 'Invalid token',
    };
  }
  
  async addApiKey(apiKey: string, user: UserInfo): Promise<void> {
    const hashedKey = await this.hashApiKey(apiKey);
    this.apiKeys.set(hashedKey, user);
    this.hashedKeys.set(hashedKey, apiKey);
  }
  
  async revokeApiKey(apiKey: string): Promise<boolean> {
    const hashedKey = await this.hashApiKey(apiKey);
    const existed = this.apiKeys.has(hashedKey);
    this.apiKeys.delete(hashedKey);
    this.hashedKeys.delete(hashedKey);
    return existed;
  }
  
  private async hashApiKey(apiKey: string): Promise<string> {
    const crypto = await import('crypto');
    return crypto
      .createHmac('sha256', this.secretKey)
      .update(apiKey)
      .digest('hex');
  }
}

// JWT Authentication Provider
export class JWTAuthProvider implements AuthenticationProvider {
  name = 'jwt';
  
  constructor(
    private secretKey: string,
    private issuer: string = 'mcp-server',
    private expirationTime: string = '1h'
  ) {}
  
  async authenticate(credentials: { username: string; password: string }): Promise<AuthenticationResult> {
    // Here you should validate the username and password
    const user = await this.validateUserCredentials(credentials.username, credentials.password);
    
    if (!user) {
      return {
        success: false,
        error: 'Invalid credentials',
      };
    }
    
    const jwt = await import('jsonwebtoken');
    const token = jwt.sign(
      {
        sub: user.id,
        username: user.username,
        roles: user.roles,
        permissions: user.permissions,
      },
      this.secretKey,
      {
        issuer: this.issuer,
        expiresIn: this.expirationTime,
      }
    );
    
    return {
      success: true,
      user,
      token,
      expiresAt: new Date(Date.now() + 3600000), // 1 hour
    };
  }
  
  async validateToken(token: string): Promise<TokenValidationResult> {
    try {
      const jwt = await import('jsonwebtoken');
      const decoded = jwt.verify(token, this.secretKey) as any;
      
      const user: UserInfo = {
        id: decoded.sub,
        username: decoded.username,
        roles: decoded.roles || [],
        permissions: decoded.permissions || [],
      };
      
      return {
        valid: true,
        user,
        expiresAt: new Date(decoded.exp * 1000),
      };
      
    } catch (error) {
      return {
        valid: false,
        error: error instanceof Error ? error.message : 'Token validation failed',
      };
    }
  }
  
  async refreshToken(refreshToken: string): Promise<RefreshTokenResult> {
    try {
      const jwt = await import('jsonwebtoken');
      const decoded = jwt.verify(refreshToken, this.secretKey) as any;
      
      // Generate a new access token
      const newToken = jwt.sign(
        {
          sub: decoded.sub,
          username: decoded.username,
          roles: decoded.roles,
          permissions: decoded.permissions,
        },
        this.secretKey,
        {
          issuer: this.issuer,
          expiresIn: this.expirationTime,
        }
      );
      
      return {
        success: true,
        token: newToken,
        refreshToken, // Keep the same refresh token
        expiresAt: new Date(Date.now() + 3600000),
      };
      
    } catch (error) {
      return {
        success: false,
        error: error instanceof Error ? error.message : 'Refresh token validation failed',
      };
    }
  }
  
  private async validateUserCredentials(username: string, password: string): Promise<UserInfo | null> {
    // Here you should query a database or other user store
    // For this example, we return a mock user
    if (username === 'admin' && password === 'password123') {
      return {
        id: 'admin-001',
        username: 'admin',
        email: 'admin@example.com',
        roles: ['admin'],
        permissions: ['*'],
      };
    }
    return null;
  }
}

// Authentication Manager
export class AuthenticationManager {
  private providers = new Map<string, AuthenticationProvider>();
  private defaultProvider?: string;
  private logger: Logger;
  
  constructor(logger: Logger) {
    this.logger = logger.child({}, 'auth');
  }
  
  registerProvider(provider: AuthenticationProvider): void {
    this.providers.set(provider.name, provider);
    if (!this.defaultProvider) {
      this.defaultProvider = provider.name;
    }
    this.logger.info(`Authentication provider registered: ${provider.name}`);
  }
  
  setDefaultProvider(name: string): void {
    if (!this.providers.has(name)) {
      throw new Error(`Provider not found: ${name}`);
    }
    this.defaultProvider = name;
  }
  
  async authenticate(
    credentials: any,
    providerName?: string
  ): Promise<AuthenticationResult> {
    const provider = this.getProvider(providerName);
    
    try {
      const result = await provider.authenticate(credentials);
      
      await this.logger.info(
        `Authentication attempt: ${result.success ? 'success' : 'failure'}`,
        {
          provider: provider.name,
          username: credentials.username || 'unknown',
          success: result.success,
        }
      );
      
      return result;
      
    } catch (error) {
      await this.logger.error(
        'Authentication error',
        error instanceof Error ? error : new Error(String(error)),
        { provider: provider.name }
      );
      
      return {
        success: false,
        error: 'Authentication system error',
      };
    }
  }
  
  async validateToken(
    token: string,
    providerName?: string
  ): Promise<TokenValidationResult> {
    const provider = this.getProvider(providerName);
    
    try {
      return await provider.validateToken(token);
    } catch (error) {
      await this.logger.error(
        'Token validation error',
        error instanceof Error ? error : new Error(String(error)),
        { provider: provider.name }
      );
      
      return {
        valid: false,
        error: 'Token validation system error',
      };
    }
  }
  
  private getProvider(name?: string): AuthenticationProvider {
    const providerName = name || this.defaultProvider;
    if (!providerName) {
      throw new Error('No authentication provider configured');
    }
    
    const provider = this.providers.get(providerName);
    if (!provider) {
      throw new Error(`Provider not found: ${providerName}`);
    }
    
    return provider;
  }
}

9.3 Authorization and Access Control

9.3.1 Role-Based Access Control (RBAC)

// src/auth/Authorization.ts
export interface Permission {
  id: string;
  name: string;
  description: string;
  resource: string;
  action: string;
  conditions?: PermissionCondition[];
}

export interface PermissionCondition {
  type: 'time' | 'ip' | 'resource_owner' | 'custom';
  operator: 'equals' | 'in' | 'not_in' | 'greater_than' | 'less_than';
  value: any;
}

export interface Role {
  id: string;
  name: string;
  description: string;
  permissions: string[]; // Permission IDs
  inherits?: string[]; // Parent role IDs
}

export interface AuthorizationContext {
  user: UserInfo;
  resource: string;
  action: string;
  metadata?: Record<string, any>;
  timestamp: Date;
  clientInfo?: {
    ip?: string;
    userAgent?: string;
  };
}

export interface AuthorizationResult {
  allowed: boolean;
  reason?: string;
  matchedPermissions?: Permission[];
  failedConditions?: PermissionCondition[];
}

export class RBACAuthorizationProvider {
  private permissions = new Map<string, Permission>();
  private roles = new Map<string, Role>();
  private logger: Logger;
  
  constructor(logger: Logger) {
    this.logger = logger.child({}, 'rbac');
    this.setupDefaultPermissions();
    this.setupDefaultRoles();
  }
  
  // Permission management
  addPermission(permission: Permission): void {
    this.permissions.set(permission.id, permission);
    this.logger.debug('Permission added', { permissionId: permission.id });
  }
  
  addRole(role: Role): void {
    // Validate permission existence
    for (const permissionId of role.permissions) {
      if (!this.permissions.has(permissionId)) {
        throw new Error(`Permission not found: ${permissionId}`);
      }
    }
    
    // Validate inherited role existence
    if (role.inherits) {
      for (const parentRoleId of role.inherits) {
        if (!this.roles.has(parentRoleId)) {
          throw new Error(`Parent role not found: ${parentRoleId}`);
        }
      }
    }
    
    this.roles.set(role.id, role);
    this.logger.debug('Role added', { roleId: role.id });
  }
  
  // Authorization check
  async authorize(context: AuthorizationContext): Promise<AuthorizationResult> {
    const userPermissions = await this.getUserPermissions(context.user);
    
    // Check for matching permissions
    const matchedPermissions: Permission[] = [];
    const failedConditions: PermissionCondition[] = [];
    
    for (const permission of userPermissions) {
      if (this.matchesResourceAndAction(permission, context.resource, context.action)) {
        // Check conditions
        const conditionResult = await this.evaluateConditions(permission, context);
        
        if (conditionResult.success) {
          matchedPermissions.push(permission);
        } else {
          failedConditions.push(...(conditionResult.failedConditions || []));
        }
      }
    }
    
    const allowed = matchedPermissions.length > 0;
    
    await this.logger.info(
      `Authorization ${allowed ? 'granted' : 'denied'}`,
      {
        userId: context.user.id,
        resource: context.resource,
        action: context.action,
        matchedPermissions: matchedPermissions.length,
        reason: allowed ? 'permissions matched' : 'no matching permissions',
      }
    );
    
    return {
      allowed,
      reason: allowed ? 'Access granted' : 'No matching permissions found',
      matchedPermissions,
      failedConditions: failedConditions.length > 0 ? failedConditions : undefined,
    };
  }
  
  // Get all permissions for a user (including inherited)
  private async getUserPermissions(user: UserInfo): Promise<Permission[]> {
    const allPermissions = new Set<Permission>();
    
    // Direct permissions
    for (const permissionId of user.permissions) {
      const permission = this.permissions.get(permissionId);
      if (permission) {
        allPermissions.add(permission);
      }
    }
    
    // Role permissions
    for (const roleId of user.roles) {
      const rolePermissions = await this.getRolePermissions(roleId);
      rolePermissions.forEach(p => allPermissions.add(p));
    }
    
    return Array.from(allPermissions);
  }
  
  // Get permissions for a role (recursively handles inheritance)
  private async getRolePermissions(roleId: string, visited = new Set<string>()): Promise<Permission[]> {
    if (visited.has(roleId)) {
      this.logger.warn('Circular role inheritance detected', { roleId });
      return [];
    }
    
    visited.add(roleId);
    
    const role = this.roles.get(roleId);
    if (!role) {
      return [];
    }
    
    const permissions = new Set<Permission>();
    
    // Direct permissions
    for (const permissionId of role.permissions) {
      const permission = this.permissions.get(permissionId);
      if (permission) {
        permissions.add(permission);
      }
    }
    
    // Inherited permissions
    if (role.inherits) {
      for (const parentRoleId of role.inherits) {
        const parentPermissions = await this.getRolePermissions(parentRoleId, new Set(visited));
        parentPermissions.forEach(p => permissions.add(p));
      }
    }
    
    return Array.from(permissions);
  }
  
  private matchesResourceAndAction(permission: Permission, resource: string, action: string): boolean {
    // Supports wildcard matching
    const resourceMatches = permission.resource === '*' || 
                           permission.resource === resource ||
                           resource.startsWith(permission.resource.replace('*', ''));
    
    const actionMatches = permission.action === '*' || 
                         permission.action === action ||
                         action.startsWith(permission.action.replace('*', ''));
    
    return resourceMatches && actionMatches;
  }
  
  private async evaluateConditions(
    permission: Permission, 
    context: AuthorizationContext
  ): Promise<{ success: boolean; failedConditions?: PermissionCondition[] }> {
    if (!permission.conditions || permission.conditions.length === 0) {
      return { success: true };
    }
    
    const failedConditions: PermissionCondition[] = [];
    
    for (const condition of permission.conditions) {
      const result = await this.evaluateCondition(condition, context);
      if (!result) {
        failedConditions.push(condition);
      }
    }
    
    return {
      success: failedConditions.length === 0,
      failedConditions: failedConditions.length > 0 ? failedConditions : undefined,
    };
  }
  
  private async evaluateCondition(condition: PermissionCondition, context: AuthorizationContext): Promise<boolean> {
    switch (condition.type) {
      case 'time':
        return this.evaluateTimeCondition(condition, context);
      
      case 'ip':
        return this.evaluateIPCondition(condition, context);
      
      case 'resource_owner':
        return this.evaluateResourceOwnerCondition(condition, context);
      
      case 'custom':
        return this.evaluateCustomCondition(condition, context);
      
      default:
        this.logger.warn('Unknown condition type', { type: condition.type });
        return false;
    }
  }
  
  private evaluateTimeCondition(condition: PermissionCondition, context: AuthorizationContext): boolean {
    const currentHour = context.timestamp.getHours();
    
    switch (condition.operator) {
      case 'greater_than':
        return currentHour > condition.value;
      case 'less_than':
        return currentHour < condition.value;
      case 'in':
        return Array.isArray(condition.value) && condition.value.includes(currentHour);
      default:
        return false;
    }
  }
  
  private evaluateIPCondition(condition: PermissionCondition, context: AuthorizationContext): boolean {
    const clientIP = context.clientInfo?.ip;
    if (!clientIP) return false;
    
    switch (condition.operator) {
      case 'equals':
        return clientIP === condition.value;
      case 'in':
        return Array.isArray(condition.value) && condition.value.includes(clientIP);
      case 'not_in':
        return Array.isArray(condition.value) && !condition.value.includes(clientIP);
      default:
        return false;
    }
  }
  
  private evaluateResourceOwnerCondition(condition: PermissionCondition, context: AuthorizationContext): boolean {
    const resourceOwner = context.metadata?.owner;
    return resourceOwner === context.user.id;
  }
  
  private evaluateCustomCondition(condition: PermissionCondition, context: AuthorizationContext): boolean {
    // Custom condition evaluation logic can be implemented here
    return false;
  }
  
  private setupDefaultPermissions(): void {
    // Tool permissions
    this.addPermission({
      id: 'tools.list',
      name: 'List Tools',
      description: 'View the list of available tools',
      resource: 'tools',
      action: 'list',
    });
    
    this.addPermission({
      id: 'tools.execute',
      name: 'Execute Tools',
      description: 'Execute tools',
      resource: 'tools',
      action: 'execute',
    });
    
    // Resource permissions
    this.addPermission({
      id: 'resources.read',
      name: 'Read Resources',
      description: 'Read resources',
      resource: 'resources',
      action: 'read',
    });
    
    this.addPermission({
      id: 'resources.write',
      name: 'Write Resources',
      description: 'Write to resources',
      resource: 'resources',
      action: 'write',
      conditions: [
        {
          type: 'resource_owner',
          operator: 'equals',
          value: true,
        },
      ],
    });
    
    // Admin permissions
    this.addPermission({
      id: 'admin.all',
      name: 'Admin All',
      description: 'Administrator permissions',
      resource: '*',
      action: '*',
    });
  }
  
  private setupDefaultRoles(): void {
    this.addRole({
      id: 'guest',
      name: 'Guest',
      description: 'Guest role',
      permissions: ['tools.list'],
    });
    
    this.addRole({
      id: 'user',
      name: 'User',
      description: 'Regular user role',
      permissions: ['tools.list', 'tools.execute', 'resources.read'],
      inherits: ['guest'],
    });
    
    this.addRole({
      id: 'admin',
      name: 'Administrator',
      description: 'Administrator role',
      permissions: ['admin.all'],
    });
  }
}

9.4 Input Validation and Data Sanitization

9.4.1 Input Validation System

// src/validation/InputValidator.ts
import { z } from 'zod';

export interface ValidationRule {
  name: string;
  schema: z.ZodSchema;
  sanitizer?: (input: any) => any;
}

export interface ValidationResult {
  valid: boolean;
  data?: any;
  errors?: ValidationError[];
  sanitizedData?: any;
}

export interface ValidationError {
  field: string;
  message: string;
  code: string;
  value?: any;
}

export class InputValidator {
  private rules = new Map<string, ValidationRule>();
  private logger: Logger;
  
  constructor(logger: Logger) {
    this.logger = logger.child({}, 'validation');
    this.setupDefaultRules();
  }
  
  addRule(name: string, rule: ValidationRule): void {
    this.rules.set(name, rule);
    this.logger.debug('Validation rule added', { name });
  }
  
  async validate(ruleName: string, input: any): Promise<ValidationResult> {
    const rule = this.rules.get(ruleName);
    if (!rule) {
      return {
        valid: false,
        errors: [{
          field: 'rule',
          message: `Validation rule not found: ${ruleName}`,
          code: 'RULE_NOT_FOUND',
        }],
      };
    }
    
    try {
      // First, sanitize the data
      const sanitizedData = rule.sanitizer ? rule.sanitizer(input) : input;
      
      // Then, perform validation
      const validatedData = rule.schema.parse(sanitizedData);
      
      return {
        valid: true,
        data: validatedData,
        sanitizedData,
      };
      
    } catch (error) {
      if (error instanceof z.ZodError) {
        const validationErrors: ValidationError[] = error.errors.map(e => ({
          field: e.path.join('.'),
          message: e.message,
          code: e.code,
          value: e.input,
        }));
        
        await this.logger.warn('Validation failed',
          {
            rule: ruleName,
            errors: validationErrors.length,
            input: this.sanitizeLogInput(input),
          }
        );
        
        return {
          valid: false,
          errors: validationErrors,
        };
      }
      
      await this.logger.error(
        'Validation error',
        error instanceof Error ? error : new Error(String(error)),
        { rule: ruleName }
      );
      
      return {
        valid: false,
        errors: [{
          field: 'validation',
          message: 'Validation system error',
          code: 'SYSTEM_ERROR',
        }],
      };
    }
  }
  
  private setupDefaultRules(): void {
    // MCP request validation
    this.addRule('mcp-request', {
      name: 'MCP Request',
      schema: z.object({
        jsonrpc: z.string().refine(v => v === '2.0'),
        id: z.union([z.string(), z.number()]).optional(),
        method: z.string().min(1).max(100),
        params: z.record(z.unknown()).optional(),
      }),
      sanitizer: (input) => ({
        ...input,
        method: typeof input?.method === 'string' ? input.method.trim() : input?.method,
      }),
    });
    
    // Tool execution parameter validation
    this.addRule('tool-execution', {
      name: 'Tool Execution',
      schema: z.object({
        name: z.string().min(1).max(100).regex(/^[a-zA-Z0-9_-]+$/),
        arguments: z.record(z.unknown()).optional(),
      }),
      sanitizer: (input) => ({
        ...input,
        name: typeof input?.name === 'string' ? input.name.trim() : input?.name,
      }),
    });
    
    // Resource URI validation
    this.addRule('resource-uri', {
      name: 'Resource URI',
      schema: z.string().min(1).max(2048).refine(uri => {
        try {
          new URL(uri);
          return true;
        } catch {
          return uri.match(/^[a-zA-Z][a-zA-Z0-9+.-]*:.+$/);
        }
      }, 'Must be a valid URI'),
      sanitizer: (input) => typeof input === 'string' ? input.trim() : input,
    });
    
    // File path validation
    this.addRule('file-path', {
      name: 'File Path',
      schema: z.string().min(1).max(4096).refine(path => {
        // Prevent path traversal attacks
        const normalizedPath = path.replace(/\\/g, '/');
        return !normalizedPath.includes('../') && 
               !normalizedPath.includes('./') &&
               !normalizedPath.startsWith('/') &&
               !normalizedPath.includes('//');
      }, 'Invalid file path'),
      sanitizer: (input) => {
        if (typeof input !== 'string') return input;
        // Normalize path separators and remove dangerous characters
        return input.replace(/\\/g, '/').replace(/[<>:"|?*]/g, '');
      },
    });
  }
  
  private sanitizeLogInput(input: any): any {
    // Avoid logging sensitive information
    if (typeof input === 'object' && input !== null) {
      const sanitized = { ...input };
      const sensitiveFields = ['password', 'token', 'apiKey', 'secret'];
      
      for (const field of sensitiveFields) {
        if (field in sanitized) {
          sanitized[field] = '[REDACTED]';
        }
      }
      
      return sanitized;
    }
    
    return input;
  }
}

// Data Sanitization Utilities
export class DataSanitizer {
  static sanitizeHtml(input: string): string {
    // Simple HTML sanitization, use a dedicated library like DOMPurify in a real application
    return input
      .replace(/</g, '&lt;')
      .replace(/>/g, '&gt;')
      .replace(/"/g, '&quot;')
      .replace(/'/g, '&#x27;')
      .replace(/\//g, '&#x2F;');
  }
  
  static sanitizeSQL(input: string): string {
    // SQL injection protection
    return input.replace(/['";\\]/g, '\\$&');
  }
  
  static sanitizeCommandLine(input: string): string {
    // Command line injection protection
    return input.replace(/[;&|`$(){}[<>*?~]/g, '\\$&');
  }
  
  static sanitizeFileName(input: string): string {
    // Filename sanitization
    return input.replace(/[^a-zA-Z0-9._-]/g, '_').substring(0, 255);
  }
  
  static limitString(input: string, maxLength: number = 1000): string {
    return input.length > maxLength ? input.substring(0, maxLength) + '...' : input;
  }
  
  static removeNullBytes(input: string): string {
    return input.replace(/\0/g, '');
  }
}

9.5 Rate Limiting and DDoS Protection

9.5.1 Request Rate Limiting

// src/security/RateLimiter.ts
export interface RateLimitConfig {
  windowMs: number; // Time window in milliseconds
  maxRequests: number; // Maximum number of requests
  skipSuccessfulRequests?: boolean; // Skip successful requests
  skipFailedRequests?: boolean; // Skip failed requests
  keyGenerator?: (context: any) => string; // Key generator
}

export interface RateLimitResult {
  allowed: boolean;
  remaining: number;
  resetTime: Date;
  retryAfter?: number; // seconds
}

export class RateLimiter {
  private requests = new Map<string, RequestRecord[]>();
  private logger: Logger;
  
  constructor(
    private config: RateLimitConfig,
    logger: Logger
  ) {
    this.logger = logger.child({}, 'rate-limiter');
    
    // Periodically clean up expired records
    setInterval(() => {
      this.cleanExpiredRecords();
    }, Math.min(this.config.windowMs, 60000)); // Clean at most once per minute
  }
  
  async checkLimit(context: any): Promise<RateLimitResult> {
    const key = this.config.keyGenerator ? this.config.keyGenerator(context) : 'default';
    const now = Date.now();
    const windowStart = now - this.config.windowMs;
    
    // Get or create request records
    let records = this.requests.get(key) || [];
    
    // Clean up expired records
    records = records.filter(record => record.timestamp > windowStart);
    
    // Calculate remaining quota
    const remaining = Math.max(0, this.config.maxRequests - records.length);
    const resetTime = new Date(now + this.config.windowMs);
    
    const result: RateLimitResult = {
      allowed: remaining > 0,
      remaining: remaining > 0 ? remaining - 1 : 0,
      resetTime,
    };
    
    if (!result.allowed) {
      // Calculate retry time
      const oldestRecord = records[0];
      if (oldestRecord) {
        result.retryAfter = Math.ceil((oldestRecord.timestamp + this.config.windowMs - now) / 1000);
      }
      
      await this.logger.warn('Rate limit exceeded',
        {
          key,
          requests: records.length,
          limit: this.config.maxRequests,
          windowMs: this.config.windowMs,
        }
      );
    }
    
    // If the request is allowed, record it
    if (result.allowed) {
      records.push({
        timestamp: now,
        success: undefined, // Will be updated after the request is completed
      });
      this.requests.set(key, records);
    }
    
    return result;
  }
  
  markRequestComplete(context: any, success: boolean): void {
    if (
      (success && this.config.skipSuccessfulRequests) ||
      (!success && this.config.skipFailedRequests)
    ) {
      const key = this.config.keyGenerator ? this.config.keyGenerator(context) : 'default';
      const records = this.requests.get(key);
      if (records && records.length > 0) {
        // Remove the last record
        records.pop();
        if (records.length === 0) {
          this.requests.delete(key);
        }
      }
    }
  }
  
  private cleanExpiredRecords(): void {
    const now = Date.now();
    const windowStart = now - this.config.windowMs;
    
    for (const [key, records] of this.requests) {
      const validRecords = records.filter(record => record.timestamp > windowStart);
      
      if (validRecords.length === 0) {
        this.requests.delete(key);
      } else if (validRecords.length < records.length) {
        this.requests.set(key, validRecords);
      }
    }
  }
  
  getStats(): { totalKeys: number; totalRequests: number } {
    let totalRequests = 0;
    for (const records of this.requests.values()) {
      totalRequests += records.length;
    }
    
    return {
      totalKeys: this.requests.size,
      totalRequests,
    };
  }
  
  reset(key?: string): void {
    if (key) {
      this.requests.delete(key);
      this.logger.info('Rate limit reset for key', { key });
    } else {
      this.requests.clear();
      this.logger.info('All rate limits reset');
    }
  }
}

interface RequestRecord {
  timestamp: number;
  success?: boolean;
}

// Multi-tier Rate Limiter
export class MultiTierRateLimiter {
  private limiters = new Map<string, RateLimiter>();
  private logger: Logger;
  
  constructor(logger: Logger) {
    this.logger = logger.child({}, 'multi-tier-limiter');
  }
  
  addTier(name: string, config: RateLimitConfig): void {
    this.limiters.set(name, new RateLimiter(config, this.logger));
    this.logger.info('Rate limit tier added', { name, config });
  }
  
  async checkAllTiers(context: any): Promise<{ allowed: boolean; tier?: string; result?: RateLimitResult }> {
    for (const [tierName, limiter] of this.limiters) {
      const result = await limiter.checkLimit(context);
      if (!result.allowed) {
        return {
          allowed: false,
          tier: tierName,
          result,
        };
      }
    }
    
    return { allowed: true };
  }
  
  markComplete(context: any, success: boolean): void {
    for (const limiter of this.limiters.values()) {
      limiter.markRequestComplete(context, success);
    }
  }
}

// Adaptive Rate Limiter
export class AdaptiveRateLimiter extends RateLimiter {
  private successRate = 1.0;
  private errorRate = 0.0;
  private adaptiveMultiplier = 1.0;
  private minMultiplier = 0.1;
  private maxMultiplier = 2.0;
  private adaptationWindow = 60000; // 1 minute
  
  constructor(config: RateLimitConfig, logger: Logger) {
    super(config, logger);
    
    // Periodically adjust the rate limit
    setInterval(() => {
      this.adjustRateLimit();
    }, this.adaptationWindow);
  }
  
  async checkLimit(context: any): Promise<RateLimitResult> {
    const baseResult = await super.checkLimit(context);
    
    // Apply adaptive adjustment
    const adjustedMaxRequests = Math.floor(this.config.maxRequests * this.adaptiveMultiplier);
    const adjustedRemaining = Math.floor(baseResult.remaining * this.adaptiveMultiplier);
    
    return {
      ...baseResult,
      allowed: adjustedRemaining > 0,
      remaining: Math.max(0, adjustedRemaining),
    };
  }
  
  recordResult(success: boolean): void {
    // Update success rate statistics
    const alpha = 0.1; // Exponential moving average coefficient
    if (success) {
      this.successRate = alpha + (1 - alpha) * this.successRate;
      this.errorRate = (1 - alpha) * this.errorRate;
    } else {
      this.errorRate = alpha + (1 - alpha) * this.errorRate;
      this.successRate = (1 - alpha) * this.successRate;
    }
  }
  
  private adjustRateLimit(): void {
    const previousMultiplier = this.adaptiveMultiplier;
    
    // Adjust rate limit based on error rate
    if (this.errorRate > 0.1) {
      // High error rate, reduce rate limit
      this.adaptiveMultiplier *= 0.8;
    } else if (this.errorRate < 0.01) {
      // Low error rate, increase rate limit
      this.adaptiveMultiplier *= 1.1;
    }
    
    // Limit adjustment range
    this.adaptiveMultiplier = Math.max(this.minMultiplier, 
                                     Math.min(this.maxMultiplier, this.adaptiveMultiplier));
    
    if (Math.abs(this.adaptiveMultiplier - previousMultiplier) > 0.01) {
      this.logger.info('Rate limit adjusted',
        {
          previousMultiplier,
          newMultiplier: this.adaptiveMultiplier,
          successRate: this.successRate,
          errorRate: this.errorRate,
        }
      );
    }
  }
}

9.6 Security Auditing and Monitoring

9.6.1 Security Event Monitoring

// src/security/SecurityMonitor.ts
export enum SecurityEventType {
  AUTHENTICATION_FAILURE = 'auth_failure',
  AUTHORIZATION_DENIED = 'auth_denied',
  SUSPICIOUS_ACTIVITY = 'suspicious_activity',
  RATE_LIMIT_EXCEEDED = 'rate_limit_exceeded',
  INPUT_VALIDATION_FAILED = 'validation_failed',
  PRIVILEGE_ESCALATION = 'privilege_escalation',
  DATA_ACCESS_VIOLATION = 'data_violation',
  SYSTEM_INTRUSION = 'intrusion',
}

export interface SecurityEvent {
  id: string;
  type: SecurityEventType;
  severity: 'low' | 'medium' | 'high' | 'critical';
  timestamp: Date;
  userId?: string;
  clientInfo?: {
    ip?: string;
    userAgent?: string;
    location?: string;
  };
  resource?: string;
  action?: string;
  details: Record<string, any>;
  metadata?: Record<string, any>;
}

export interface SecurityAlert {
  id: string;
  event: SecurityEvent;
  threshold: SecurityThreshold;
  count: number;
  firstOccurrence: Date;
  lastOccurrence: Date;
  status: 'active' | 'resolved' | 'suppressed';
}

export interface SecurityThreshold {
  eventType: SecurityEventType;
  count: number;
  windowMs: number;
  severity: 'low' | 'medium' | 'high' | 'critical';
  actions: SecurityAction[];
}

export enum SecurityAction {
  LOG_ALERT = 'log_alert',
  SEND_EMAIL = 'send_email',
  BLOCK_USER = 'block_user',
  BLOCK_IP = 'block_ip',
  RATE_LIMIT = 'rate_limit',
  REQUIRE_MFA = 'require_mfa',
}

export class SecurityMonitor {
  private events: SecurityEvent[] = [];
  private alerts = new Map<string, SecurityAlert>();
  private thresholds: SecurityThreshold[] = [];
  private eventCounters = new Map<string, { count: number; windowStart: number }>();
  private logger: Logger;
  private maxEvents = 10000;
  
  constructor(logger: Logger) {
    this.logger = logger.child({}, 'security-monitor');
    this.setupDefaultThresholds();
    
    // Periodically clean up old events
    setInterval(() => {
      this.cleanupOldEvents();
    }, 300000); // Every 5 minutes
  }
  
  async recordEvent(event: Omit<SecurityEvent, 'id' | 'timestamp'>): Promise<void> {
    const securityEvent: SecurityEvent = {
      ...event,
      id: this.generateEventId(),
      timestamp: new Date(),
    };
    
    // Record event
    this.events.push(securityEvent);
    
    // Limit number of events
    if (this.events.length > this.maxEvents) {
      this.events.shift();
    }
    
    // Log event
    await this.logger.warn(
      `Security event: ${event.type}`,
      {
        eventId: securityEvent.id,
        type: event.type,
        severity: event.severity,
        userId: event.userId,
        resource: event.resource,
        action: event.action,
        details: event.details,
      }
    );
    
    // Check if a threshold has been triggered
    await this.checkThresholds(securityEvent);
  }
  
  private async checkThresholds(event: SecurityEvent): Promise<void> {
    for (const threshold of this.thresholds) {
      if (threshold.eventType === event.type) {
        await this.evaluateThreshold(threshold, event);
      }
    }
  }
  
  private async evaluateThreshold(threshold: SecurityThreshold, event: SecurityEvent): Promise<void> {
    const key = `${threshold.eventType}:${event.userId || 'anonymous'}:${event.clientInfo?.ip || 'unknown'}`;
    const now = Date.now();
    const windowStart = now - threshold.windowMs;
    
    // Clean up expired counts
    const counter = this.eventCounters.get(key);
    if (!counter || counter.windowStart < windowStart) {
      this.eventCounters.set(key, { count: 1, windowStart: now });
      return;
    }
    
    // Increment count
    counter.count++;
    
    // Check if the threshold has been exceeded
    if (counter.count >= threshold.count) {
      await this.triggerAlert(threshold, event, counter.count);
    }
  }
  
  private async triggerAlert(threshold: SecurityThreshold, event: SecurityEvent, count: number): Promise<void> {
    const alertId = this.generateAlertId();
    const alert: SecurityAlert = {
      id: alertId,
      event,
      threshold,
      count,
      firstOccurrence: new Date(Date.now() - threshold.windowMs), // Approximate first occurrence
      lastOccurrence: event.timestamp,
      status: 'active',
    };
    
    this.alerts.set(alertId, alert);
    
    await this.logger.error(
      `Security alert triggered: ${threshold.eventType}`,
      {
        alertId,
        eventType: threshold.eventType,
        count,
        threshold: threshold.count,
        windowMs: threshold.windowMs,
        severity: threshold.severity,
      }
    );
    
    // Execute security actions
    await this.executeSecurityActions(threshold, event);
  }
  
  private async executeSecurityActions(threshold: SecurityThreshold, event: SecurityEvent): Promise<void> {
    for (const action of threshold.actions) {
      try {
        await this.executeSecurityAction(action, threshold, event);
      } catch (error) {
        await this.logger.error(
          'Security action execution failed',
          error instanceof Error ? error : new Error(String(error)),
          { action, eventType: threshold.eventType }
        );
      }
    }
  }
  
  private async executeSecurityAction(action: SecurityAction, threshold: SecurityThreshold, event: SecurityEvent): Promise<void> {
    switch (action) {
      case SecurityAction.LOG_ALERT:
        await this.logger.error(
          `SECURITY ALERT: ${threshold.eventType} threshold exceeded`,
          {
            severity: threshold.severity,
            eventId: event.id,
            userId: event.userId,
            ip: event.clientInfo?.ip,
          }
        );
        break;
      
      case SecurityAction.BLOCK_USER:
        if (event.userId) {
          // Should call a user management system in a real implementation
          await this.logger.warn('User blocking requested', { userId: event.userId });
        }
        break;
      
      case SecurityAction.BLOCK_IP:
        if (event.clientInfo?.ip) {
          // Should call a firewall or network layer in a real implementation
          await this.logger.warn('IP blocking requested', { ip: event.clientInfo.ip });
        }
        break;
      
      case SecurityAction.SEND_EMAIL:
        // Should send an email notification in a real implementation
        await this.logger.info('Email notification requested', { eventType: threshold.eventType });
        break;
      
      default:
        await this.logger.warn('Unknown security action', { action });
    }
  }
  
  getEvents(filter?: {
    type?: SecurityEventType;
    severity?: string;
    userId?: string;
    since?: Date;
    limit?: number;
  }): SecurityEvent[] {
    let filtered = this.events;
    
    if (filter) {
      if (filter.type) {
        filtered = filtered.filter(e => e.type === filter.type);
      }
      if (filter.severity) {
        filtered = filtered.filter(e => e.severity === filter.severity);
      }
      if (filter.userId) {
        filtered = filtered.filter(e => e.userId === filter.userId);
      }
      if (filter.since) {
        filtered = filtered.filter(e => e.timestamp >= filter.since!);
      }
    }
    
    // Sort in reverse chronological order
    filtered.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());
    
    // Apply limit
    if (filter?.limit) {
      filtered = filtered.slice(0, filter.limit);
    }
    
    return filtered;
  }
  
  getActiveAlerts(): SecurityAlert[] {
    return Array.from(this.alerts.values())
      .filter(alert => alert.status === 'active')
      .sort((a, b) => b.lastOccurrence.getTime() - a.lastOccurrence.getTime());
  }
  
  resolveAlert(alertId: string): boolean {
    const alert = this.alerts.get(alertId);
    if (alert) {
      alert.status = 'resolved';
      return true;
    }
    return false;
  }
  
  private setupDefaultThresholds(): void {
    this.thresholds = [
      {
        eventType: SecurityEventType.AUTHENTICATION_FAILURE,
        count: 5,
        windowMs: 300000, // 5 minutes
        severity: 'medium',
        actions: [SecurityAction.LOG_ALERT, SecurityAction.RATE_LIMIT],
      },
      {
        eventType: SecurityEventType.AUTHORIZATION_DENIED,
        count: 10,
        windowMs: 600000, // 10 minutes
        severity: 'medium',
        actions: [SecurityAction.LOG_ALERT],
      },
      {
        eventType: SecurityEventType.RATE_LIMIT_EXCEEDED,
        count: 3,
        windowMs: 60000, // 1 minute
        severity: 'low',
        actions: [SecurityAction.LOG_ALERT],
      },
      {
        eventType: SecurityEventType.PRIVILEGE_ESCALATION,
        count: 1,
        windowMs: 3600000, // 1 hour
        severity: 'critical',
        actions: [SecurityAction.LOG_ALERT, SecurityAction.SEND_EMAIL, SecurityAction.BLOCK_USER],
      },
    ];
  }
  
  private generateEventId(): string {
    return `event_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
  }
  
  private generateAlertId(): string {
    return `alert_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
  }
  
  private cleanupOldEvents(): void {
    const cutoff = new Date(Date.now() - 24 * 60 * 60 * 1000); // 24 hours ago
    this.events = this.events.filter(event => event.timestamp > cutoff);
    
    // Clean up expired counters
    const now = Date.now();
    for (const [key, counter] of this.eventCounters) {
      if (counter.windowStart < now - 3600000) { // 1 hour ago
        this.eventCounters.delete(key);
      }
    }
  }
}

9.7 Integration Example: Secure MCP Server

// src/SecureMCPServer.ts
export class SecureMCPServer extends EnhancedMCPServer {
  private authManager: AuthenticationManager;
  private rbacProvider: RBACAuthorizationProvider;
  private inputValidator: InputValidator;
  private rateLimiter: MultiTierRateLimiter;
  private securityMonitor: SecurityMonitor;
  
  constructor(config: ServerConfig & { security: SecurityConfig }) {
    super(config);
    this.setupSecurity(config.security);
  }
  
  private setupSecurity(securityConfig: SecurityConfig): void {
    // Authentication management
    this.authManager = new AuthenticationManager(this.logger);
    if (securityConfig.authentication.methods.includes(AuthMethod.API_KEY)) {
      const apiKeyProvider = new ApiKeyAuthProvider(process.env.API_KEY_SECRET || 'default-secret');
      this.authManager.registerProvider(apiKeyProvider);
    }
    if (securityConfig.authentication.methods.includes(AuthMethod.JWT)) {
      const jwtProvider = new JWTAuthProvider(process.env.JWT_SECRET || 'default-secret');
      this.authManager.registerProvider(jwtProvider);
    }
    
    // Authorization management
    this.rbacProvider = new RBACAuthorizationProvider(this.logger);
    
    // Input validation
    this.inputValidator = new InputValidator(this.logger);
    
    // Rate limiting
    this.rateLimiter = new MultiTierRateLimiter(this.logger);
    this.setupRateLimiting(securityConfig.rateLimiting);
    
    // Security monitoring
    this.securityMonitor = new SecurityMonitor(this.logger);
  }
  
  private setupRateLimiting(config: any): void {
    if (!config.enabled) return;
    
    // Global rate limiting
    this.rateLimiter.addTier('global', {
      windowMs: config.windowMs,
      maxRequests: config.maxRequests,
      keyGenerator: () => 'global',
    });
    
    // User-level rate limiting
    this.rateLimiter.addTier('user', {
      windowMs: config.windowMs,
      maxRequests: Math.floor(config.maxRequests / 2),
      keyGenerator: (context) => `user:${context.userId || 'anonymous'}`,
    });
    
    // IP-level rate limiting
    this.rateLimiter.addTier('ip', {
      windowMs: config.windowMs,
      maxRequests: Math.floor(config.maxRequests * 2),
      keyGenerator: (context) => `ip:${context.clientIP || 'unknown'}`,
    });
  }
  
  // Enhanced request handling method
  async handleSecureRequest(request: Request, context: {
    clientIP?: string;
    userAgent?: string;
    authHeader?: string;
  }): Promise<Response> {
    const requestId = `req_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
    const startTime = new Date();
    
    try {
      // 1. Input validation
      const validationResult = await this.inputValidator.validate('mcp-request', request);
      if (!validationResult.valid) {
        await this.securityMonitor.recordEvent({
          type: SecurityEventType.INPUT_VALIDATION_FAILED,
          severity: 'medium',
          clientInfo: { ip: context.clientIP, userAgent: context.userAgent },
          details: { errors: validationResult.errors },
        });
        
        return {
          jsonrpc: '2.0',
          id: request.id,
          error: MCPErrorBuilder.invalidParams('Input validation failed', validationResult.errors),
        };
      }
      
      // 2. Authentication
      let user: UserInfo | undefined;
      if (context.authHeader) {
        const authResult = await this.authManager.validateToken(context.authHeader);
        if (!authResult.valid) {
          await this.securityMonitor.recordEvent({
            type: SecurityEventType.AUTHENTICATION_FAILURE,
            severity: 'medium',
            clientInfo: { ip: context.clientIP, userAgent: context.userAgent },
            details: { error: authResult.error },
          });
          
          return {
            jsonrpc: '2.0',
            id: request.id,
            error: {
              code: MCPErrorCode.AUTHENTICATION_FAILED,
              message: 'Authentication failed',
            },
          };
        }
        user = authResult.user;
      }
      
      // 3. Rate limit check
      const rateLimitContext = {
        userId: user?.id,
        clientIP: context.clientIP,
      };
      
      const rateLimitResult = await this.rateLimiter.checkAllTiers(rateLimitContext);
      if (!rateLimitResult.allowed) {
        await this.securityMonitor.recordEvent({
          type: SecurityEventType.RATE_LIMIT_EXCEEDED,
          severity: 'low',
          userId: user?.id,
          clientInfo: { ip: context.clientIP },
          details: { tier: rateLimitResult.tier },
        });
        
        return {
          jsonrpc: '2.0',
          id: request.id,
          error: {
            code: MCPErrorCode.RATE_LIMIT_EXCEEDED,
            message: 'Rate limit exceeded',
            data: {
              retryAfter: rateLimitResult.result?.retryAfter,
              resetTime: rateLimitResult.result?.resetTime,
            },
          },
        };
      }
      
      // 4. Authorization check (if needed)
      if (user && this.requiresAuthorization(request.method)) {
        const authzContext: AuthorizationContext = {
          user,
          resource: this.getResourceFromMethod(request.method),
          action: this.getActionFromMethod(request.method),
          timestamp: startTime,
          clientInfo: { ip: context.clientIP, userAgent: context.userAgent },
          metadata: request.params,
        };
        
        const authzResult = await this.rbacProvider.authorize(authzContext);
        if (!authzResult.allowed) {
          await this.securityMonitor.recordEvent({
            type: SecurityEventType.AUTHORIZATION_DENIED,
            severity: 'medium',
            userId: user.id,
            resource: authzContext.resource,
            action: authzContext.action,
            clientInfo: { ip: context.clientIP },
            details: { reason: authzResult.reason },
          });
          
          return {
            jsonrpc: '2.0',
            id: request.id,
            error: {
              code: MCPErrorCode.AUTHORIZATION_FAILED,
              message: 'Authorization denied',
              data: { reason: authzResult.reason },
            },
          };
        }
      }
      
      // 5. Handle the request
      const response = await this.handleRequest(request);
      
      // 6. Mark rate limiting as complete
      this.rateLimiter.markComplete(rateLimitContext, !response.error);
      
      return response;
      
    } catch (error) {
      // Log system error
      await this.securityMonitor.recordEvent({
        type: SecurityEventType.SYSTEM_INTRUSION,
        severity: 'high',
        userId: user?.id,
        clientInfo: { ip: context.clientIP },
        details: { error: error instanceof Error ? error.message : String(error) },
      });
      
      this.rateLimiter.markComplete({ userId: user?.id, clientIP: context.clientIP }, false);
      
      return {
        jsonrpc: '2.0',
        id: request.id,
        error: {
          code: MCPErrorCode.INTERNAL_ERROR,
          message: 'Internal server error',

}