MCP

Aegisv1

Advanced Patterns

Complex pattern matching techniques and combinations.

MCP Aegis's advanced patterns provide sophisticated validation capabilities including pattern negation, case-insensitive matching, and complex pattern combinations. These patterns enable flexible and powerful test assertions for complex MCP server behaviors.

Pattern Negation

Pattern negation allows you to invert any pattern using the "match:not:" prefix. This is incredibly powerful for testing what should not happen in your MCP server responses.

How Pattern Negation Works

Pattern negation works with any existing pattern. Simply prefix the pattern with not: to invert its result.

Basic Negation Examples

yaml
# Test that values are NOT certain things
expect:
  response:
    result:
      # String negations
      status: "match:not:contains:error"        # Should NOT contain "error"
      message: "match:not:startsWith:FAIL"      # Should NOT start with "FAIL"
      output: "match:not:endsWith:.tmp"         # Should NOT end with ".tmp"
      
      # Type negations  
      data: "match:not:type:string"             # Should NOT be a string
      result: "match:not:type:null"             # Should NOT be null
      
      # Array negations
      tools: "match:not:arrayLength:0"          # Array should NOT be empty
      items: "match:not:arrayContains:deleted"  # Should NOT contain "deleted"
      
      # Numeric negations
      errorRate: "match:not:greaterThan:5"      # Should NOT be > 5 (i.e., <= 5)
      score: "match:not:between:0:50"           # Should NOT be 0-50 (i.e., > 50)

Complex Negation Patterns

yaml
# Advanced negation with field extraction and array patterns
expect:
  response:
    result:
      # Field extraction with negation
      tools:
        match:extractField: "*.name"
        value: "match:not:arrayContains:deprecated_tool"  # No deprecated tools
      
      # Array elements with negation
      tools:
        match:arrayElements:
          name: "match:not:startsWith:invalid_"     # No invalid tool names
          status: "match:not:contains:disabled"     # No disabled tools
          description: "match:not:type:null"        # All must have descriptions
      
      # Partial matching with negation
      config:
        match:partial:
          debug: "match:not:type:boolean"           # Debug should not be boolean
          logLevel: "match:not:contains:TRACE"      # Should not contain TRACE

Production Negation Examples

yaml
# Real-world examples from MCP Aegis test suite
- it: "should ensure API response contains no error indicators"
  request:
    jsonrpc: "2.0"
    id: "error-check"
    method: "tools/call"
    params:
      name: "process_data"
      arguments:
        input: "valid-data.json"
  expect:
    response:
      jsonrpc: "2.0"
      id: "error-check"
      result:
        status: "match:not:contains:error"          # No error in status
        warnings: "match:not:arrayLength:0"         # Should have warnings array but not necessarily empty
        output: "match:not:type:null"               # Output should exist
        processingTime: "match:not:greaterThan:5000" # Should not take > 5 seconds
      stderr: "match:not:contains:Exception"        # No exceptions in stderr

Case-Insensitive Patterns

Case-insensitive patterns allow flexible string matching regardless of capitalization, perfect for handling user input, API responses with varying case, or cross-platform compatibility.

Case-Insensitive Contains

Use "match:containsIgnoreCase:TEXT" to check if a string contains a substring, ignoring case differences.

yaml
# Match regardless of case
expect:
  response:
    result:
      message: "match:containsIgnoreCase:success"   # Matches "Success", "SUCCESS", "success"
      status: "match:containsIgnoreCase:ok"         # Matches "OK", "Ok", "ok"  
      type: "match:containsIgnoreCase:json"         # Matches "JSON", "Json", "json"
      
      # Works with error messages too
      errorDetails: "match:containsIgnoreCase:not found"  # Matches various case combinations

Case-Insensitive Equals

Use "match:equalsIgnoreCase:TEXT" for exact string matching while ignoring case.

yaml
# Exact match ignoring case
expect:
  response:
    result:
      protocol: "match:equalsIgnoreCase:http"       # Matches "HTTP", "Http", "http"
      method: "match:equalsIgnoreCase:get"          # Matches "GET", "Get", "get"
      contentType: "match:equalsIgnoreCase:application/json"  # Case-insensitive MIME type
      
      # Boolean-like strings
      enabled: "match:equalsIgnoreCase:true"        # Matches "True", "TRUE", "true"

Case-Insensitive with Arrays

yaml
# Case-insensitive matching works with arrays too
expect:
  response:
    result:
      # Search within array elements
      tags: "match:containsIgnoreCase:important"    # Finds "IMPORTANT", "Important", etc.
      
      # Use with field extraction
      tools:
        match:extractField: "*.category"
        value: "match:containsIgnoreCase:utility"   # Case-insensitive category search

Case-Insensitive Production Examples

yaml
# Example handling API responses with inconsistent casing
- it: "should handle API responses with varying case formats"
  request:
    jsonrpc: "2.0"
    id: "case-test"
    method: "tools/call"
    params:
      name: "fetch_api_data"
      arguments:
        endpoint: "https://api.example.com/status"
  expect:
    response:
      jsonrpc: "2.0"
      id: "case-test"
      result:
        # Handle different API response case formats
        status: "match:equalsIgnoreCase:active"      # "ACTIVE", "Active", "active"
        protocol: "match:containsIgnoreCase:https"    # Various HTTPS representations
        responseType: "match:containsIgnoreCase:json" # "JSON", "Json", "application/json"
        
        # Case-insensitive error detection
        errorMessage: "match:not:containsIgnoreCase:failed"  # No failure indicators
        warningLevel: "match:not:equalsIgnoreCase:critical"  # Not critical warnings

Utility Patterns

Additional utility patterns for specialized validation scenarios.

Field Existence

Use "match:exists" to validate that a field exists (not null or undefined).

yaml
# Validate field presence
expect:
  response:
    result:
      timestamp: "match:exists"           # Field must exist (not null/undefined)
      metadata: "match:exists"            # Object must exist
      optional: "match:exists"            # Even optional fields can be validated for existence
      
      # Combine with negation for optional fields
      debugInfo: "match:not:exists"       # Field should NOT exist in production

Object Property Counting

Use "match:count:N" to validate the number of properties in an object.

yaml
# Validate object structure by property count
expect:
  response:
    result:
      metadata: "match:count:3"           # Object must have exactly 3 properties
      config: "match:count:5"             # Configuration object has 5 settings
      
      # Use with negation for flexible bounds
      optionalData: "match:not:count:0"   # Object should not be empty

Pattern Combinations

Advanced techniques for combining multiple patterns in sophisticated test scenarios.

Multi-Level Validation

yaml
# Complex validation combining multiple pattern types
- it: "should validate complex API response with multiple patterns"
  request:
    jsonrpc: "2.0"
    id: "complex"
    method: "tools/call"
    params:
      name: "get_user_data"
      arguments:
        userId: "12345"
  expect:
    response:
      jsonrpc: "2.0"
      id: "complex"
      result:
        # Type validation first
        users: "match:type:array"
        
        # Then array-specific validation
        users: "match:not:arrayLength:0"            # Not empty
        
        # Field extraction with negation and case-insensitive matching
        users:
          match:extractField: "*.status"
          value: "match:not:containsIgnoreCase:inactive"  # No inactive users
        
        # Array elements with multiple pattern types  
        users:
          match:arrayElements:
            id: "match:type:string"                   # Type validation
            name: "match:not:contains:null"           # No null names
            email: "match:containsIgnoreCase:@"       # Valid email indicator
            createdAt: "match:greaterThan:0"          # Valid timestamp
            score: "match:between:0:100"              # Valid score range
            active: "match:equalsIgnoreCase:true"     # Active users only
            
        # Overall response validation
        totalCount: "match:greaterThanOrEqual:1"      # At least one user
        hasMore: "match:type:boolean"                 # Pagination indicator
        nextCursor: "match:not:type:null"             # Cursor should exist

Conditional Pattern Strategies

yaml
# Strategy: Use separate tests for different scenarios rather than complex conditionals
- it: "should validate successful response format"
  request:
    # ... success case request
  expect:
    response:
      result:
        success: "match:equalsIgnoreCase:true"
        data: "match:type:object"
        error: "match:not:exists"                    # Error should not exist
        
- it: "should validate error response format"  
  request:
    # ... error case request  
  expect:
    response:
      result:
        success: "match:equalsIgnoreCase:false"
        data: "match:not:exists"                     # Data should not exist
        error: "match:type:object"
        error:
          code: "match:type:number"
          message: "match:type:string"
          details: "match:not:containsIgnoreCase:internal" # No internal error details

Best Practices for Advanced Patterns

Pattern Negation Best Practices

  • Be Specific: Use specific negations rather than broad ones
  • Test Both Sides: Create both positive and negative test cases
  • Clear Intent: Make test descriptions clear about what you're testing NOT to happen
  • Avoid Double Negatives: Don't negate negated patterns unnecessarily

Case-Insensitive Best Practices

  • API Consistency: Use case-insensitive patterns for external APIs
  • User Input: Always use case-insensitive for user-generated content
  • Configuration Values: Use for configuration that might vary in case
  • Cross-Platform: Essential for file paths and system responses

Pattern Combination Best Practices

  • Layer Validation: Start with type validation, then specific patterns
  • Separate Concerns: Use multiple test cases rather than one complex test
  • Readable Tests: Keep individual pattern applications simple and clear
  • Performance: Consider the cost of complex pattern combinations

Performance Consideration

Complex pattern combinations can be computationally expensive. For performance-critical tests, consider using simpler patterns or breaking complex validations into multiple focused test cases.

Common Use Cases

  • Security Testing: Ensure sensitive data doesn't appear in responses
  • Cross-Platform Compatibility: Handle varying case formats across systems
  • Error Detection: Validate absence of error indicators
  • API Contract Testing: Ensure responses don't contain deprecated fields
  • Data Quality: Validate data doesn't contain invalid or null values
  • Internationalization: Handle text in multiple languages and cases