Reference¶
This page provides a complete reference for MCP Server Fuzzer, including all command-line options, API documentation, and configuration details.
Command-Line Reference¶
Basic Syntax¶
mcp-fuzzer [OPTIONS] --mode {tools|protocol|resources|prompts|all} --protocol {http|sse|stdio|streamablehttp} --endpoint ENDPOINT
Global Options¶
| Option | Type | Default | Description |
|---|---|---|---|
--help | Flag | - | Show help message and exit |
--verbose | Flag | False | Enable verbose logging |
--log-level | Choice | WARNING (INFO with --verbose) | Set log level (CRITICAL, ERROR, WARNING, INFO, DEBUG). Defaults to WARNING, or INFO when --verbose is set |
Utility Options¶
| Option | Type | Default | Description |
|---|---|---|---|
--validate-config | Path | - | Validate configuration file and exit |
--check-env | Flag | False | Validate environment variables and exit |
Mode Options¶
| Option | Type | Required | Description |
|---|---|---|---|
--mode | Choice | Yes | Fuzzing mode: tools, protocol, resources, prompts, or all |
--protocol | Choice | Yes | Transport protocol: http, sse, stdio, or streamablehttp |
--endpoint | String | Yes | Server endpoint (URL for http/sse, command for stdio) |
Transport Options¶
| Option | Type | Default | Description |
|---|---|---|---|
--timeout | Float | 30.0 | Request timeout in seconds |
--auth-config | Path | - | Path to authentication configuration file |
--auth-env | Flag | False | Use authentication from environment variables |
Notes:
-
When using
--protocol streamablehttpthe client: -
Performs an automatic MCP initialize handshake before the first request.
- Propagates
mcp-session-idandmcp-protocol-versionheaders after negotiation. - Follows 307/308 redirects (e.g., adds a trailing slash
/mcp/).
Fuzzing Options¶
| Option | Type | Default | Description |
|---|---|---|---|
--phase | Choice | aggressive | Fuzzing phase: realistic, aggressive, or both |
--runs | Integer | 10 | Number of fuzzing runs per tool (tool mode only) |
--runs-per-type | Integer | 5 | Number of runs per protocol/resource/prompt type |
--protocol-type | String | - | Fuzz only a specific protocol type (protocol mode only; required by the CLI when using --mode protocol) |
Spec Guard Options¶
| Option | Type | Default | Description |
|---|---|---|---|
--spec-guard | Bool | True | Run deterministic spec guard checks before protocol/resources/prompts fuzzing |
--spec-resource-uri | String | - | Resource URI used for spec guard resources/read checks |
--spec-prompt-name | String | - | Prompt name used for spec guard prompts/get checks |
--spec-prompt-args | String | - | JSON string of prompt arguments for spec guard prompts/get checks |
Safety Options¶
| Option | Type | Default | Description |
|---|---|---|---|
--enable-safety-system | Flag | False | Enable system-level safety features |
--no-safety | Flag | False | Disable argument-level safety filtering |
--fs-root | Path | ~/.mcp_fuzzer | Restrict filesystem operations to specified directory |
--retry-with-safety-on-interrupt | Flag | False | Retry once with safety system enabled on Ctrl-C |
Network Options¶
| Option | Type | Default | Description |
|---|---|---|---|
--no-network | Flag | False | Disallow network to non-local hosts |
--allow-host | String | - | Permit additional hostnames when --no-network is set (repeatable) |
Reporting Options¶
| Option | Type | Default | Description |
|---|---|---|---|
--output-dir | Path | reports | Directory to save reports and exports |
--safety-report | Flag | False | Show comprehensive safety report at end of fuzzing |
--export-safety-data | String | - | Export safety data to JSON file (optional filename) |
--output-format | Choice | json | Output format for standardized reports |
--output-types | List | - | Output types to generate (fuzzing_results, error_report, safety_summary, performance_metrics, configuration_dump) |
--output-schema | Path | - | Path to custom output schema file |
--output-compress | Flag | False | Compress output files |
--output-session-id | String | - | Custom session ID for output files |
Notes:
- Standardized output files are currently emitted as JSON;
--output-formatis accepted for compatibility.
Export Options¶
| Option | Type | Default | Description |
|---|---|---|---|
--export-csv | Path | - | Export fuzzing results to CSV format |
--export-xml | Path | - | Export fuzzing results to XML format |
--export-html | Path | - | Export fuzzing results to HTML format |
--export-markdown | Path | - | Export fuzzing results to Markdown format |
Runtime Options¶
| Option | Type | Default | Description |
|---|---|---|---|
--watchdog-check-interval | Float | 1.0 | How often to check processes for hanging (seconds) |
--watchdog-process-timeout | Float | 30.0 | Time before a process is considered hanging (seconds) |
--watchdog-extra-buffer | Float | 5.0 | Extra time before auto-kill (seconds) |
--watchdog-max-hang-time | Float | 60.0 | Maximum time before force kill (seconds) |
--process-max-concurrency | Integer | 5 | Maximum concurrent process operations |
--max-concurrency | Integer | 5 | Maximum concurrent client operations |
--process-retry-count | Integer | 1 | Number of retries for failed operations |
--process-retry-delay | Float | 1.0 | Delay between retries (seconds) |
Advanced Options¶
| Option | Type | Default | Description |
|---|---|---|---|
--tool-timeout | Float | - | Per-tool call timeout in seconds (defaults to --timeout when unset) |
--enable-aiomonitor | Flag | False | Enable AIOMonitor for async debugging (connect with telnet localhost 20101) |
Configuration Reference¶
Environment Variables¶
| Variable | Default | Description |
|---|---|---|
MCP_FUZZER_TIMEOUT | 30.0 | Default timeout for all operations |
MCP_FUZZER_LOG_LEVEL | INFO | Default log level |
MCP_FUZZER_SAFETY_ENABLED | false | Enable safety system by default |
MCP_FUZZER_FS_ROOT | ~/.mcp_fuzzer | Default filesystem root for safety |
MCP_FUZZER_HTTP_TIMEOUT | 30.0 | HTTP transport timeout |
MCP_FUZZER_SSE_TIMEOUT | 30.0 | SSE transport timeout |
MCP_FUZZER_STDIO_TIMEOUT | 30.0 | Stdio transport timeout |
Authentication Environment Variables¶
| Variable | Description |
|---|---|
MCP_API_KEY | API key for authentication |
MCP_HEADER_NAME | Header name for API key (default: Authorization) |
MCP_PREFIX | Prefix for API key value (default: Bearer) |
MCP_USERNAME | Username for basic authentication |
MCP_PASSWORD | Password for basic authentication |
MCP_OAUTH_TOKEN | OAuth token for authentication |
MCP_CUSTOM_HEADERS | Custom headers as JSON string for authentication |
MCP_TOOL_AUTH_MAPPING | Map tool names to auth providers as JSON |
Authentication System Reference¶
Authentication Providers¶
The authentication system supports multiple provider types with configurable options:
API Key Authentication¶
{
"type": "api_key",
"api_key": "YOUR_API_KEY",
"header_name": "Authorization",
"prefix": "Bearer"
}
- api_key (required): The API key value
- header_name (optional): HTTP header to place the key in (default: "Authorization")
- prefix (optional): Value prefix for the header (default: "Bearer"). Set to empty string for no prefix.
Basic Authentication¶
- username (required): Username for basic auth
- password (required): Password for basic auth
OAuth Token Authentication¶
- token (required): OAuth token value
- token_type (optional): Token type for Authorization header (default: "Bearer")
Custom Headers Authentication¶
{
"type": "custom",
"headers": {
"X-Custom-Header": "value",
"X-Another-Header": "another-value"
}
}
- headers (required): Dictionary of custom headers to include
Tool-to-Auth Mapping¶
Map specific tools to authentication providers:
{
"tool_mapping": {
"openai_chat": "openai_api",
"github_search": "github_api",
"default_tool": "basic_auth"
}
}
Error Messages¶
The authentication system provides detailed error messages for configuration issues:
- Missing required fields indicate which provider type and field is missing
- Expected configuration format is provided in error messages
- Type validation errors show the received vs. expected type
Runtime Management API Reference¶
The runtime management system provides robust, asynchronous subprocess lifecycle management for transports and target servers under test.
ProcessManager¶
The ProcessManager provides fully asynchronous subprocess lifecycle management with comprehensive process tracking and signal handling.
Class Definition¶
class ProcessManager:
def __init__(self, config: Optional[WatchdogConfig] = None):
"""Initialize the async process manager."""
Configuration¶
@dataclass
class ProcessConfig:
command: List[str] # Command and arguments to execute
cwd: Optional[Union[str, Path]] = None # Working directory
env: Optional[Dict[str, str]] = None # Environment variables
timeout: float = 30.0 # Default timeout for operations
auto_kill: bool = True # Whether to auto-kill hanging processes
name: str = "unknown" # Human-readable name for logging
activity_callback: Optional[Callable[[], float]] = None # Activity callback
Methods¶
async start_process(config: ProcessConfig) -> asyncio.subprocess.Process- Start a new process asynchronously
- Returns the created subprocess object
-
Automatically registers process with watchdog
-
async stop_process(pid: int, force: bool = False) -> bool - Stop a running process gracefully or forcefully
- Returns True if process was stopped successfully
-
Uses SIGTERM for graceful, SIGKILL for force
-
async stop_all_processes(force: bool = False) -> None - Stop all running processes
- Can be graceful or forceful
-
Executes concurrently for all processes
-
async get_process_status(pid: int) -> Optional[Dict[str, Any]] - Get detailed status information for a specific process
- Returns None if process is not managed
-
Includes start time, status, and configuration
-
async list_processes() -> List[Dict[str, Any]] - Get list of all managed processes with their status
-
Returns comprehensive process information
-
async wait(pid: int, timeout: Optional[float] = None) -> Optional[int] - Wait for a process to complete
- Returns exit code or None if timeout
-
Non-blocking with configurable timeout
-
async update_activity(pid: int) -> None - Update activity timestamp for a process
-
Used for hang detection by watchdog
-
async get_stats() -> Dict[str, Any] - Get overall statistics about managed processes
-
Includes process counts by status and watchdog stats
-
async cleanup_finished_processes() -> int - Remove finished processes from tracking
- Returns count of cleaned processes
-
Prevents resource leaks
-
async shutdown() -> None - Shutdown the process manager and stop all processes
-
Ensures proper cleanup of all resources
-
async send_timeout_signal(pid: int, signal_type: str = "timeout") -> bool - Send a timeout signal to a running process
- Signal types: "timeout", "force", "interrupt"
-
Returns True if signal was sent successfully
-
async register_existing_process(pid: int, process: asyncio.subprocess.Process, name: Optional[str] = None, activity_callback: Optional[Callable[[], float]] = None, *, config: Optional[ProcessConfig] = None) -> None - Register an already-started subprocess with the manager
- Useful for integrating with existing process management
Usage Examples¶
from mcp_fuzzer.fuzz_engine.runtime.manager import ProcessManager, ProcessConfig
async def process_manager_example():
manager = ProcessManager.from_config()
# Start a process
config = ProcessConfig(
command=["python", "test_server.py"],
name="test_server",
timeout=60.0
)
process = await manager.start_process(config)
# Monitor process
status = await manager.get_process_status(process.pid)
print(f"Process {process.pid} status: {status['status']}")
# Update activity
await manager.update_activity(process.pid)
# Get statistics
stats = await manager.get_stats()
print(f"Managing {stats['total_managed']} processes")
# Stop process
await manager.stop_process(process.pid)
# Cleanup
await manager.shutdown()
ProcessWatchdog¶
The ProcessWatchdog provides automated monitoring and termination of hanging processes with configurable thresholds and activity tracking.
Class Definition¶
class ProcessWatchdog:
def __init__(self, config: Optional[WatchdogConfig] = None):
"""Initialize the process watchdog."""
Configuration¶
@dataclass
class WatchdogConfig:
check_interval: float = 1.0 # How often to check processes (seconds)
process_timeout: float = 30.0 # Time before process is considered hanging (seconds)
extra_buffer: float = 5.0 # Extra time before auto-kill (seconds)
max_hang_time: float = 60.0 # Maximum time before force kill (seconds)
auto_kill: bool = True # Whether to automatically kill hanging processes
Methods¶
async start() -> None-
Start the watchdog monitoring loop; creates background task for monitoring
-
async stop() -> None -
Stop the monitoring loop and cancel/await the background task
-
async scan_once(processes: dict[int, ProcessRecord]) -> dict[str, Any] -
Run one hang-detection pass against a registry snapshot
-
async update_activity(pid: int) -> None -
Update activity timestamp for a process pulled from the registry
-
async get_stats() -> dict - Get statistics about monitored processes and the watchdog loop state
Note: processes are added to the shared ProcessRegistry (or by ProcessLifecycle.start), and the watchdog reads that registry instead of maintaining its own table.
Context Manager Support¶
async with ProcessWatchdog(registry, dispatcher, config) as watchdog:
await registry.register(pid, process, ProcessConfig(command=["python"], name=name))
await watchdog.update_activity(pid)
# ... registry keeps the process table; watchdog reads it
Usage Examples¶
import asyncio
import logging
from mcp_fuzzer.fuzz_engine.runtime import (
ProcessConfig,
ProcessRegistry,
ProcessWatchdog,
SignalDispatcher,
WatchdogConfig,
)
async def watchdog_example():
registry = ProcessRegistry()
dispatcher = SignalDispatcher(registry, logging.getLogger(__name__))
watchdog = ProcessWatchdog(
registry,
dispatcher,
WatchdogConfig(check_interval=1.0, process_timeout=30.0, auto_kill=True),
)
await watchdog.start()
# Register a process via the registry
process = await asyncio.create_subprocess_exec("python", "server.py")
await registry.register(
process.pid,
process,
ProcessConfig(command=["python", "server.py"], name="server"),
)
# Update activity periodically
for _ in range(10):
await watchdog.update_activity(process.pid)
await asyncio.sleep(5)
# Get statistics
stats = await watchdog.get_stats()
print(f"Monitoring {stats['total_processes']} processes")
await watchdog.stop()
AsyncFuzzExecutor¶
The AsyncFuzzExecutor provides controlled concurrency for fuzzing operations using semaphore-based concurrency control.
Class Definition¶
class AsyncFuzzExecutor:
def __init__(
self,
max_concurrency: int = 5, # Maximum concurrent operations
):
Methods¶
async execute_batch(operations: List[Tuple[Callable, List[Any], Dict[str, Any]]]) -> Dict[str, List[Any]]- Execute a batch of operations concurrently with bounded concurrency
- Operations are tuples of
(callable, args, kwargs) - Returns dictionary with
'results'and'errors'lists - Errors are automatically collected; successful results in
'results' -
Handles both async and sync operations (sync runs in thread pool)
-
async run_hypothesis_strategy(strategy: st.SearchStrategy) -> Any - Run a Hypothesis strategy in thread pool to prevent asyncio deadlocks
-
Returns generated value from the strategy
-
async shutdown() -> None - Shutdown the executor and clean up thread pool resources
- Waits for thread pool to complete all tasks
Usage Examples¶
from mcp_fuzzer.fuzz_engine.executor import AsyncFuzzExecutor
async def executor_example():
executor = AsyncFuzzExecutor(max_concurrency=3)
try:
# Define async operation
async def sample_operation(value):
await asyncio.sleep(0.5)
return f"processed_{value}"
# Prepare operations as (function, args, kwargs) tuples
operations = [
(sample_operation, [i], {}) for i in range(10)
]
# Execute batch with automatic error collection
results = await executor.execute_batch(operations)
print(f"Results: {len(results['results'])}, Errors: {len(results['errors'])}")
finally:
await executor.shutdown()
CLI Improvements¶
The MCP Server Fuzzer CLI has been enhanced with better user experience features:
Progress Indicators¶
The CLI now provides clear progress indicators during fuzzing operations:
# Progress indicators show current status
mcp-fuzzer --mode tools --protocol http --endpoint http://localhost:8000 --runs 100
# Output: [████████████████████████████████████████] 100% Complete
Enhanced Error Messages¶
Error messages now include suggested fixes and context:
# Before: "Connection failed"
# After: "Connection failed: Unable to connect to http://localhost:8000
# Suggested fixes:
# - Check if the server is running
# - Verify the endpoint URL is correct
# - Check firewall settings"
Interactive Help¶
The CLI provides interactive help for complex configurations:
# Show help for specific mode
mcp-fuzzer --mode tools --help
# Show help for specific protocol
mcp-fuzzer --protocol stdio --help
Argument Validation¶
The CLI now validates argument combinations and provides helpful error messages:
# Invalid combination detection
mcp-fuzzer --mode protocol
# Error: --protocol-type is required when --mode protocol
# Missing required arguments
mcp-fuzzer --mode tools
# Error: --endpoint is required for fuzzing operations
Verbose Output Improvements¶
Enhanced verbose output provides more detailed information:
# Verbose mode shows detailed execution information
mcp-fuzzer --mode tools --protocol http --endpoint http://localhost:8000 --verbose
# Output includes:
# - Tool discovery progress
# - Individual test execution details
# - Safety system actions
# - Performance metrics
Error Handling and Recovery¶
Graceful Error Handling¶
The CLI handles errors gracefully with proper cleanup:
# Interrupt handling (Ctrl+C)
mcp-fuzzer --mode tools --protocol stdio --endpoint "python server.py" --runs 100
# Press Ctrl+C
# Output: "Fuzzing interrupted. Cleaning up processes..."
# "Use --retry-with-safety-on-interrupt to retry with safety enabled"
Retry Mechanisms¶
Built-in retry mechanisms for transient failures:
# Automatic retry on connection failures
mcp-fuzzer --mode tools --protocol http --endpoint http://localhost:8000 --runs 10
# If connection fails, automatically retries with exponential backoff
Safety Integration¶
Enhanced safety integration with better user feedback:
# Safety system status reporting
mcp-fuzzer --mode tools --protocol stdio --endpoint "python server.py" --enable-safety-system
# Output: "Safety system enabled. Monitoring for dangerous operations..."
# "Blocked 3 file operations outside sandbox"
# "Safety report: 5 operations blocked, 2 warnings issued"
Output Formatting Improvements¶
Rich Console Output¶
Enhanced console output with better formatting:
# Colorized output with better table formatting
mcp-fuzzer --mode tools --protocol http --endpoint http://localhost:8000 --runs 10
# Output includes:
# - Color-coded success/failure indicators
# - Progress bars for long operations
# - Formatted tables with proper alignment
# - Summary statistics with visual indicators
Report Generation¶
Improved report generation with better organization:
# Enhanced report generation
mcp-fuzzer --mode tools --protocol stdio --endpoint "python server.py" --runs 20 \
--safety-report \
--export-safety-data \
--output-dir "detailed_reports"
# Generates:
# - Comprehensive JSON report with metadata
# - Human-readable text summary
# - Safety-specific report with risk analysis
# - Session metadata and configuration
Configuration Validation¶
Environment Variable Validation¶
The CLI validates environment variables and provides helpful messages:
# Invalid environment variable detection
export MCP_FUZZER_TIMEOUT="invalid"
mcp-fuzzer --mode tools --protocol http --endpoint http://localhost:8000
# Error: Invalid timeout value 'invalid'. Must be a positive number.
# Current value: MCP_FUZZER_TIMEOUT=invalid
# Suggested fix: export MCP_FUZZER_TIMEOUT=30.0
Configuration File Validation¶
Enhanced configuration file validation:
# Configuration file validation
mcp-fuzzer --mode tools --config invalid_config.yaml
# Error: Configuration file validation failed:
# - Line 5: 'timeout' must be a number, got 'invalid'
# - Line 10: 'protocol' must be one of ['http', 'sse', 'stdio', 'streamablehttp']
# Suggested fixes:
# - Fix timeout value on line 5
# - Use valid protocol on line 10
Performance Monitoring¶
Real-time Performance Metrics¶
The CLI provides real-time performance monitoring:
# Performance monitoring during execution
mcp-fuzzer --mode tools --protocol http --endpoint http://localhost:8000 --runs 100 --verbose
# Output includes:
# - Requests per second
# - Average response time
# - Memory usage
# - CPU usage
# - Error rate trends
Resource Usage Reporting¶
Enhanced resource usage reporting:
# Resource usage summary
mcp-fuzzer --mode tools --protocol stdio --endpoint "python server.py" --runs 50
# Output: "Resource usage summary:"
# " CPU usage: 15.2% average"
# " Memory usage: 45.3 MB peak"
# " Network I/O: 2.1 MB total"
# " Process count: 3 managed"
Debugging and Troubleshooting¶
Enhanced Debug Output¶
Improved debug output for troubleshooting:
# Debug mode with detailed information
mcp-fuzzer --mode tools --protocol http --endpoint http://localhost:8000 --log-level DEBUG
# Output includes:
# - Detailed request/response logging
# - Safety system decision logging
# - Process management events
# - Performance timing information
Diagnostic Information¶
Additional Export Formats¶
The MCP Server Fuzzer supports multiple export formats for reports:
CSV Export¶
Export fuzzing results to CSV format for analysis in spreadsheet applications:
# Export to CSV format
mcp-fuzzer --mode tools --protocol http --endpoint http://localhost:8000 --runs 20 --export-csv results.csv
CSV output includes: - Tool name - Run number - Success status - Response time - Exception message (if any) - Arguments used - Timestamp
XML Export¶
Export fuzzing results to XML format for integration with XML-based tools:
# Export to XML format
mcp-fuzzer --mode tools --protocol http --endpoint http://localhost:8000 --runs 20 --export-xml results.xml
HTML Export¶
Export results to HTML format for web-based reporting:
# Export to HTML format
mcp-fuzzer --mode tools --protocol http --endpoint http://localhost:8000 --runs 20 --export-html results.html
Markdown Export¶
Export results to Markdown format for documentation:
# Export to Markdown format
mcp-fuzzer --mode tools --protocol http --endpoint http://localhost:8000 --runs 20 --export-markdown results.md
Notes:
- JSON and text reports are always written to
--output-dir. - Export flags create additional artifacts in the same output directory.
Export Format Comparison¶
| Format | Use Case | Notes |
|---|---|---|
| JSON | Programmatic analysis | Generated automatically in the output directory |
| CSV | Spreadsheet analysis | Simple tabular summary |
| XML | Enterprise integration | Structured, verbose |
| HTML | Web reporting | Human-readable |
| Markdown | Documentation | Works well in repos and wikis |
Famous Open Source MCP Server Fuzz Results¶
For detailed fuzzing results and security analysis of popular open source MCP servers, see the Fuzz Results documentation.
This section provides comprehensive testing results for various MCP server implementations, including vulnerability assessments, performance metrics, and security recommendations.
API Reference¶
Package Layout and Fuzz Engine¶
The codebase is organized around a modular fuzz engine with clear boundaries between generation (mutators), orchestration (executors), and execution (runtime):
mcp_fuzzer/
fuzz_engine/
mutators/
tool_mutator.py # Generates fuzzed tool arguments
protocol_mutator.py # Generates fuzzed protocol envelopes
batch_mutator.py # Generates JSON-RPC batch requests
strategies/
schema_parser.py # JSON Schema parser for test data generation
strategy_manager.py # Realistic/aggressive strategy selection
realistic/
tool_strategy.py
protocol_type_strategy.py
aggressive/
tool_strategy.py
protocol_type_strategy.py
executor/
tool_executor.py # Orchestrates tool fuzzing (uses AsyncFuzzExecutor)
protocol_executor.py # Orchestrates protocol-type fuzzing + invariants
batch_executor.py # Orchestrates batch fuzzing
invariants.py # Property-based invariants and checks
runtime/
manager.py # Async ProcessManager (start/stop, signals)
watchdog.py # ProcessWatchdog (hang detection)
wrapper.py # Async helpers/executor wrapper
transport/
interfaces/driver.py # TransportDriver interface
drivers/http_driver.py # JSON over HTTP
drivers/sse_driver.py # Server-Sent Events
drivers/stdio_driver.py # STDIO transport
drivers/stream_http_driver.py # Streamable HTTP (JSON + SSE, session headers)
catalog/builder.py # build_driver(...)
reports/
reporter/ # Aggregates results + DI plumbing
formatters/ # Console/JSON/Text/HTML/etc. formatters
output/ # Standardized output protocol + manager
safety_reporter.py # Safety-specific report
safety_system/
safety.py # SafetyFilter and SafetyProvider protocol
blocking/ # PATH shim command blocker + shims
command_blocker.py
shims/
detection/ # DangerDetector patterns and helpers
detector.py
patterns.py
filesystem/ # Filesystem sandbox + path sanitizer
sandbox.py
sanitizer.py
cli/
parser.py, entrypoint.py, validators.py, config_merge.py
client/
main.py # UnifiedMCPFuzzerClient orchestrator
Schema Parser¶
The schema parser module (mcp_fuzzer.fuzz_engine.mutators.strategies.schema_parser) provides comprehensive support for parsing JSON Schema definitions and generating appropriate test data based on schema specifications.
Features¶
- Basic Types: Handles string, number, integer, boolean, array, object, and null types
- String Constraints: Supports minLength, maxLength, pattern, and format validations
- Number/Integer Constraints: Handles minimum, maximum, exclusiveMinimum, exclusiveMaximum, multipleOf
- Array Constraints: Supports minItems, maxItems, uniqueItems
- Object Constraints: Handles required properties, minProperties, additionalProperties (false blocks extra properties)
- Schema Combinations: Processes oneOf, anyOf, allOf schema combinations with proper constraint merging
- Enums and Constants: Supports enum values and const keyword (both in realistic and aggressive modes)
- Fuzzing Phases: Supports both "realistic" (valid) and "aggressive" (edge cases) modes
Example Usage¶
from mcp_fuzzer.fuzz_engine.mutators.strategies.schema_parser import (
make_fuzz_strategy_from_jsonschema
)
# Define a JSON schema
schema = {
"type": "object",
"properties": {
"name": {"type": "string", "minLength": 3, "maxLength": 50},
"age": {"type": "integer", "minimum": 18, "maximum": 120},
"email": {"type": "string", "format": "email"}
},
"required": ["name", "age"]
}
# Generate realistic data
realistic_data = make_fuzz_strategy_from_jsonschema(schema, phase="realistic")
# Generate aggressive data for security testing
aggressive_data = make_fuzz_strategy_from_jsonschema(schema, phase="aggressive")
Invariants System¶
The invariants module (mcp_fuzzer.fuzz_engine.executor.invariants) provides property-based testing capabilities to verify response validity, error type correctness, and prevention of unintended crashes or unexpected states during fuzzing.
Features¶
- Response Validity: Ensures responses follow JSON-RPC 2.0 specification
- Error Type Correctness: Verifies error responses have correct structure and codes
- Schema Conformity: Validates responses against JSON schema definitions
- Batch Verification: Applies invariant checks to batches of responses
- State Consistency: Ensures server state remains consistent during fuzzing
Example Usage¶
from mcp_fuzzer.fuzz_engine.executor.invariants import (
verify_response_invariants,
InvariantViolation
)
# Verify a response against invariants
try:
verify_response_invariants(
response={"jsonrpc": "2.0", "id": 1, "result": "success"},
expected_error_codes=[400, 404, 500],
schema={"type": "object", "properties": {"result": {"type": "string"}}}
)
# Response is valid
except InvariantViolation as e:
# Invariant violation detected
print(f"Violation: {e}")
- Mutators: Generate inputs for tools and protocol types in two phases:
- realistic (valid/spec-conformant), aggressive (malformed/attack vectors).
- Executors: Run mutators, send envelopes via a transport, and record results.
- Runtime: Manages subprocess lifecycles with a watchdog for hang/timeout handling.
- Transport: Pluggable I/O. Use
--protocol http|sse|stdio|streamablehttp.
Fuzz Engine lifecycle (high level)¶
- Client builds a
TransportDrivervia the factory. - For tools:
ToolExecutororchestratesToolMutatorto generate args, integrates with safety system, and executes via transport. - For protocol:
ProtocolExecutororchestratesProtocolMutatorto generate JSON-RPC envelopes, validates invariants, and sends raw via transport. - All executors use
AsyncFuzzExecutorfor concurrent execution with bounded concurrency. - Runtime ensures external processes (when used) are supervised and terminated safely.
See Fuzz Engine Architecture for detailed information about the modular design.
Runtime¶
The runtime layer provides robust, asynchronous subprocess lifecycle management for transports and target servers under test.
- Components:
ProcessManager(async): start/stop processes, send signals, await exit, collect stats; integrates with the watchdog.ProcessWatchdog: monitors registered PIDs for hangs/inactivity and terminates them based on policy.-
All operations are now fully asynchronous using native asyncio.
-
Behavior and guarantees:
-
Fully async API; blocking calls (spawn, wait, kill) run in thread executors.
- Process-group signaling on POSIX to prevent orphan children.
- Safe stop flow: TERM (grace window) → KILL on timeout if needed.
-
Watchdog uses the shared registry; call
start()/stop()explicitly (or via context manager) and unregisters completed/hung processes after a scan. -
Typical usage:
-
Transports that spawn servers should use
ProcessManager.start_process(...)and register activity callbacks. - For externally spawned subprocesses (e.g.,
asyncio.create_subprocess_exec), register with the watchdog to enable hang detection and timeouts.
Transport Protocol Interface¶
The core interface for transport protocols:
from abc import ABC, abstractmethod
from typing import Any, Dict, Optional, AsyncIterator
class TransportDriver(ABC):
"""Abstract base class for transport protocols."""
@abstractmethod
async def send_request(self, method: str, params: Optional[Dict[str, Any]] = None) -> Any:
"""Send a JSON-RPC request to the server."""
pass
@abstractmethod
async def send_raw(self, payload: Dict[str, Any]) -> Any:
"""Send raw payload to the server."""
pass
@abstractmethod
async def send_notification(self, method: str, params: Optional[Dict[str, Any]] = None) -> None:
"""Send a JSON-RPC notification to the server."""
pass
async def connect(self) -> None:
"""Connect to the transport (optional override)."""
pass
async def disconnect(self) -> None:
"""Disconnect from the transport (optional override)."""
pass
async def stream_request(self, payload: Dict[str, Any]) -> AsyncIterator[Dict[str, Any]]:
"""Stream a request and yield response chunks."""
pass
@abstractmethod
async def _stream_request(self, payload: Dict[str, Any]) -> AsyncIterator[Dict[str, Any]]:
"""Transport-specific streaming implementation."""
pass
Fuzzer Client¶
The main client for orchestrating fuzzing operations:
from mcp_fuzzer.client import MCPFuzzerClient
from mcp_fuzzer.safety_system.safety import SafetyFilter
class UnifiedMCPFuzzerClient:
"""Unified client for MCP fuzzing operations."""
def __init__(
self,
transport: TransportDriver,
safety_system: Optional[SafetyFilter] = None,
):
self.transport = transport
self.safety_system = safety_system or SafetyFilter()
async def fuzz_tools(self, runs: int = 10, phase: str = "aggressive"):
"""Fuzz tools with specified number of runs and phase."""
# Implementation details mirror mcp_fuzzer.client.base.MCPFuzzerClient
async def fuzz_protocol(
self, runs_per_type: int = 5, protocol_type: Optional[str] = None, phase: str = "aggressive"
):
"""Fuzz protocol types with specified parameters."""
# Implementation details...
Safety System¶
Core safety system for protecting against dangerous operations:
from mcp_fuzzer.safety_system.safety import SafetyFilter
safety = SafetyFilter()
safety.set_fs_root("/tmp/mcp_sandbox")
tool_args = {"url": "https://example.com", "output_path": "/etc/passwd"}
sanitized = safety.sanitize_tool_arguments("web_tool", tool_args)
if safety.should_skip_tool_call("web_tool", tool_args):
safe_response = safety.create_safe_mock_response("web_tool")
else:
# Proceed with sanitized arguments
transport.call_tool("web_tool", sanitized)
SafetyFilter combines the pattern-based DangerDetector, filesystem path sanitization, and blocked operation logging. For system-level protection call mcp_fuzzer.safety_system.blocking.start_system_blocking() to install PATH shims that intercept browser launches.
Fuzzing Strategies¶
Realistic Strategies¶
Generate realistic, valid data for tool testing:
class RealisticToolStrategy:
"""Generates realistic, valid data for tool testing."""
def generate_string(self) -> str:
"""Generate realistic string values."""
return draw(st.text(min_size=1, max_size=100))
def generate_number(self) -> Union[int, float]:
"""Generate realistic numeric values."""
return draw(st.one_of(st.integers(), st.floats()))
def generate_boolean(self) -> bool:
"""Generate boolean values."""
return draw(st.booleans())
Aggressive Strategies¶
Generate malicious/malformed data for security testing:
class AggressiveToolStrategy:
"""Generates malicious/malformed data for security testing."""
def generate_sql_injection(self) -> str:
"""Generate SQL injection attempts."""
return draw(st.sampled_from([
"' OR 1=1; --",
"'; DROP TABLE users; --",
"' UNION SELECT * FROM users --"
]))
def generate_xss(self) -> str:
"""Generate XSS attack attempts."""
return draw(st.sampled_from([
"<script>alert('xss')</script>",
"javascript:alert('xss')",
"<img src=x onerror=alert('xss')>"
]))
Output Format¶
Tool Fuzzer Results¶
{
"tools": [
{
"name": "tool_name",
"success_rate": 85.0,
"total_runs": 10,
"successful_runs": 8,
"exception_count": 2,
"exceptions": [
"Invalid argument type",
"Missing required parameter"
],
"average_response_time": 0.15
}
],
"overall": {
"total_tools": 3,
"total_runs": 30,
"overall_success_rate": 90.0,
"total_exceptions": 3
}
}
Protocol Fuzzer Results¶
{
"protocol_types": [
{
"name": "InitializeRequest",
"total_runs": 5,
"successful_runs": 5,
"exception_count": 0,
"success_rate": 100.0,
"exceptions": [],
"average_response_time": 0.12
}
],
"overall": {
"total_protocol_types": 19,
"total_runs": 95,
"overall_success_rate": 93.3,
"total_exceptions": 5
}
}
Safety System Reference¶
The safety system focuses on containment and preventing external references during fuzzing.
- Argument-level filtering (
mcp_fuzzer.safety_system.safety.SafetyFilter): - Blocks URLs and risky commands in tool arguments; recursively sanitizes dicts/lists.
- CLI provides
--fs-rootto redirect sandbox. -
set_fs_root(path)records a sandbox root (for future path checks). -
System-level blocking (
mcp_fuzzer.safety_system.blocking.command_blocker.SystemCommandBlocker): - Creates PATH shims for
xdg-open,open,start, and common browsers to prevent app launches. -
Enabled with
--enable-safety-system; helper functions live inmcp_fuzzer.safety_system.blocking. -
Policy utilities (
mcp_fuzzer.safety_system.policy): is_host_allowed(url, allowed_hosts=None, deny_network_by_default=None)resolve_redirect_safely(base_url, location, ...)(same-origin + allow-list)sanitize_subprocess_env(env)strips proxy env vars before spawning subprocesses-
sanitize_headers(headers)removes sensitive outbound headers by default -
Safety Options (CLI Flags):
--no-network: Disallow non-local hosts.-
--allow-host HOST: Add to allow-list (bare hostname/IP, no scheme/port). Repeatable. -
Network and Proxy Policies:
- HTTP transports are created with environment proxies disabled (
trust_env=False), so environment proxy variables are ignored. - Only same-origin 307 and 308 redirects are automatically followed, and only after checking the host allow-list policy via
is_host_allowed.
Performance Tuning¶
Timeout Configuration¶
# Increase timeouts for slow servers
mcp-fuzzer --mode tools --protocol http --endpoint http://localhost:8000 --timeout 120.0 --tool-timeout 60.0
# Set different timeouts for different transports
export MCP_FUZZER_HTTP_TIMEOUT=60.0
export MCP_FUZZER_SSE_TIMEOUT=90.0
export MCP_FUZZER_STDIO_TIMEOUT=30.0
Concurrency Settings¶
# High-volume testing
mcp-fuzzer --mode tools --protocol http --endpoint http://localhost:8000 --runs 100
# Multiple concurrent instances
mcp-fuzzer --mode tools --protocol http --endpoint http://localhost:8000 --runs 50 &
mcp-fuzzer --mode tools --protocol http --endpoint http://localhost:8001 --runs 50 &
wait
Debugging Reference¶
Log Levels¶
| Level | Description | Use Case |
|---|---|---|
CRITICAL | Critical errors only | Production monitoring |
ERROR | Error conditions | Error tracking |
WARNING | Warning messages | Issue identification |
INFO | General information | Normal operation |
DEBUG | Detailed debugging | Development/debugging |
Verbose Output¶
# Enable verbose logging
mcp-fuzzer --mode tools --protocol http --endpoint http://localhost:8000 --verbose
# Set specific log level
mcp-fuzzer --mode tools --protocol http --endpoint http://localhost:8000 --log-level DEBUG
# Combine options
mcp-fuzzer --mode tools --protocol http --endpoint http://localhost:8000 --verbose --log-level DEBUG
Error Handling¶
# Handle timeouts gracefully
mcp-fuzzer --mode tools --protocol http --endpoint http://localhost:8000 --timeout 60.0
# Retry with safety on interrupt
mcp-fuzzer --mode tools --protocol stdio --endpoint "python test_server.py" --retry-with-safety-on-interrupt
# Custom tool timeout
mcp-fuzzer --mode tools --protocol http --endpoint http://localhost:8000 --tool-timeout 30.0
Configuration Files¶
Authentication Configuration¶
{
"providers": {
"openai_api": {
"type": "api_key",
"api_key": "sk-your-openai-api-key",
"header_name": "Authorization"
},
"github_api": {
"type": "api_key",
"api_key": "ghp-your-github-token",
"header_name": "Authorization"
},
"basic_auth": {
"type": "basic",
"username": "user",
"password": "password"
}
},
"tool_mapping": {
"openai_chat": "openai_api",
"github_search": "github_api",
"secure_tool": "basic_auth"
}
}
This reference covers all the major aspects of MCP Server Fuzzer. For more detailed information about specific components, see the Architecture and Examples documentation.