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
# 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
# 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 TRACEProduction Negation Examples
# 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 stderrCase-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.
# 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 combinationsCase-Insensitive Equals
Use "match:equalsIgnoreCase:TEXT" for exact string matching while ignoring case.
# 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
# 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 searchCase-Insensitive Production Examples
# 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 warningsUtility Patterns
Additional utility patterns for specialized validation scenarios.
Field Existence
Use "match:exists" to validate that a field exists (not null or undefined).
# 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 productionObject Property Counting
Use "match:count:N" to validate the number of properties in an object.
# 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 emptyPattern Combinations
Advanced techniques for combining multiple patterns in sophisticated test scenarios.
Multi-Level Validation
# 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 existConditional Pattern Strategies
# 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 detailsBest 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