Skip to content

Commit 2380c37

Browse files
committed
redesign
1 parent c07d6bf commit 2380c37

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+2048
-427
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ doc_ref/
1818
# C extensions
1919
*REDESIGN*.md
2020
*FLOW.md
21+
*USAGE.md
2122
*.so
2223
notes.md
2324
/reports/

mcp_fuzzer/cli/config_merge.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
import logging
88
from typing import Any
99

10-
from ..config import config as global_config, load_config_file, apply_config_file
1110
from ..exceptions import ConfigFileError
11+
from ..client.adapters import config_mediator
1212
from ..client.settings import CliConfig
1313
from ..client.transport.auth_port import resolve_auth_port
1414
from .parser import create_argument_parser
@@ -60,7 +60,7 @@ def _transfer_config_to_args(args: argparse.Namespace) -> None:
6060
]
6161

6262
for config_key, args_key in mapping:
63-
config_value = global_config.get(config_key)
63+
config_value = config_mediator.get(config_key)
6464
default_value = defaults_parser.get_default(args_key)
6565
if default_value is argparse.SUPPRESS: # pragma: no cover
6666
default_value = None
@@ -73,15 +73,15 @@ def build_cli_config(args: argparse.Namespace) -> CliConfig:
7373
"""Merge CLI args, config files, and resolved auth."""
7474
if args.config:
7575
try:
76-
loaded = load_config_file(args.config)
77-
global_config.update(loaded)
76+
loaded = config_mediator.load_file(args.config)
77+
config_mediator.update(loaded)
7878
except Exception as exc:
7979
raise ConfigFileError(
8080
f"Failed to load configuration file '{args.config}': {exc}"
8181
)
8282
else:
8383
try:
84-
apply_config_file()
84+
config_mediator.apply_file()
8585
except Exception as exc:
8686
logging.debug(f"Error loading default configuration file: {exc}")
8787

@@ -135,7 +135,7 @@ def build_cli_config(args: argparse.Namespace) -> CliConfig:
135135
"auth_manager": auth_manager,
136136
}
137137

138-
global_config.update(merged)
138+
config_mediator.update(merged)
139139
return CliConfig(args=args, merged=merged)
140140

141141

mcp_fuzzer/cli/startup_info.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ def print_startup_info(args: argparse.Namespace, config: dict | None = None) ->
2626
try:
2727
# Load and display the config file content
2828
import json
29-
from ..config import load_config_file
30-
raw_config = load_config_file(args.config)
29+
from ..client.adapters import config_mediator
30+
raw_config = config_mediator.load_file(args.config)
3131
config_json = json.dumps(raw_config, indent=2, sort_keys=True)
3232
console.print(f"[dim]{config_json}[/dim]")
3333
console.print()

mcp_fuzzer/cli/validators.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from rich.console import Console
1212

1313
from ..exceptions import ArgumentValidationError
14-
from ..config import load_config_file
14+
from ..client.adapters import config_mediator
1515
from ..transport.factory import create_transport
1616
from ..exceptions import MCPError, TransportError
1717
from ..env import ENVIRONMENT_VARIABLES, ValidationType
@@ -65,7 +65,7 @@ def validate_arguments(self, args: argparse.Namespace) -> None:
6565

6666
def validate_config_file(self, path: str) -> None:
6767
"""Validate a config file and print success message."""
68-
load_config_file(path)
68+
config_mediator.load_file(path)
6969
success_msg = (
7070
"[green]:heavy_check_mark: Configuration file "
7171
f"'{path}' is valid[/green]"

mcp_fuzzer/client/__init__.py

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,72 @@
11
"""Public client exports."""
22

33
from .base import MCPFuzzerClient
4+
from .adapters import ConfigAdapter, config_mediator
5+
from .constants import (
6+
CONTENT_TYPE_HEADER,
7+
DEFAULT_FORCE_KILL_TIMEOUT,
8+
DEFAULT_GRACEFUL_SHUTDOWN_TIMEOUT,
9+
DEFAULT_HTTP_ACCEPT,
10+
DEFAULT_MAX_TOTAL_FUZZING_TIME,
11+
DEFAULT_MAX_TOOL_TIME,
12+
DEFAULT_PROTOCOL_RUNS_PER_TYPE,
13+
DEFAULT_PROTOCOL_VERSION,
14+
DEFAULT_TIMEOUT,
15+
DEFAULT_TOOL_RUNS,
16+
DEFAULT_TOOL_TIMEOUT,
17+
JSON_CONTENT_TYPE,
18+
MCP_PROTOCOL_VERSION_HEADER,
19+
MCP_SESSION_ID_HEADER,
20+
PROCESS_CLEANUP_TIMEOUT,
21+
PROCESS_FORCE_KILL_TIMEOUT,
22+
PROCESS_TERMINATION_TIMEOUT,
23+
PROCESS_WAIT_TIMEOUT,
24+
SAFETY_ENV_ALLOWLIST,
25+
SAFETY_HEADER_DENYLIST,
26+
SAFETY_LOCAL_HOSTS,
27+
SAFETY_NO_NETWORK_DEFAULT,
28+
SAFETY_PROXY_ENV_DENYLIST,
29+
SSE_CONTENT_TYPE,
30+
WATCHDOG_DEFAULT_CHECK_INTERVAL,
31+
WATCHDOG_EXTRA_BUFFER,
32+
WATCHDOG_MAX_HANG_ADDITIONAL,
33+
)
34+
from .ports import ConfigPort
435

536
UnifiedMCPFuzzerClient = MCPFuzzerClient
637

7-
__all__ = ["MCPFuzzerClient", "UnifiedMCPFuzzerClient"]
38+
__all__ = [
39+
"MCPFuzzerClient",
40+
"UnifiedMCPFuzzerClient",
41+
"ConfigPort",
42+
"ConfigAdapter",
43+
"config_mediator",
44+
# Constants
45+
"DEFAULT_PROTOCOL_VERSION",
46+
"CONTENT_TYPE_HEADER",
47+
"JSON_CONTENT_TYPE",
48+
"SSE_CONTENT_TYPE",
49+
"DEFAULT_HTTP_ACCEPT",
50+
"MCP_SESSION_ID_HEADER",
51+
"MCP_PROTOCOL_VERSION_HEADER",
52+
"WATCHDOG_DEFAULT_CHECK_INTERVAL",
53+
"WATCHDOG_EXTRA_BUFFER",
54+
"WATCHDOG_MAX_HANG_ADDITIONAL",
55+
"SAFETY_LOCAL_HOSTS",
56+
"SAFETY_NO_NETWORK_DEFAULT",
57+
"SAFETY_HEADER_DENYLIST",
58+
"SAFETY_PROXY_ENV_DENYLIST",
59+
"SAFETY_ENV_ALLOWLIST",
60+
"DEFAULT_TOOL_RUNS",
61+
"DEFAULT_PROTOCOL_RUNS_PER_TYPE",
62+
"DEFAULT_TIMEOUT",
63+
"DEFAULT_TOOL_TIMEOUT",
64+
"DEFAULT_MAX_TOOL_TIME",
65+
"DEFAULT_MAX_TOTAL_FUZZING_TIME",
66+
"DEFAULT_GRACEFUL_SHUTDOWN_TIMEOUT",
67+
"DEFAULT_FORCE_KILL_TIMEOUT",
68+
"PROCESS_TERMINATION_TIMEOUT",
69+
"PROCESS_FORCE_KILL_TIMEOUT",
70+
"PROCESS_CLEANUP_TIMEOUT",
71+
"PROCESS_WAIT_TIMEOUT",
72+
]
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#!/usr/bin/env python3
2+
"""Adapter implementations for Port and Adapter pattern.
3+
4+
Adapters implement the ports (interfaces) by adapting external modules.
5+
This is where the mediation between modules happens.
6+
"""
7+
8+
from .config_adapter import ConfigAdapter, config_mediator
9+
10+
__all__ = ["ConfigAdapter", "config_mediator"]
11+
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
#!/usr/bin/env python3
2+
"""Configuration adapter implementation for Port and Adapter pattern.
3+
4+
This module implements the ConfigPort interface by adapting the config module.
5+
This is the adapter that mediates all configuration access.
6+
"""
7+
8+
from __future__ import annotations
9+
10+
from typing import Any
11+
12+
from ...config import (
13+
apply_config_file,
14+
get_config_schema,
15+
load_config_file,
16+
)
17+
from ...config.core.manager import config as global_config
18+
from ..ports.config_port import ConfigPort
19+
20+
21+
class ConfigAdapter(ConfigPort):
22+
"""Adapter that implements ConfigPort by delegating to the config module.
23+
24+
This adapter acts as a mediator between other modules and the config module,
25+
implementing the Port and Adapter (Hexagonal Architecture) pattern.
26+
"""
27+
28+
def __init__(self, config_instance: Any = None):
29+
"""Initialize the config adapter.
30+
31+
Args:
32+
config_instance: Optional configuration instance to use.
33+
If None, uses the global config instance.
34+
"""
35+
self._config = config_instance or global_config
36+
37+
def get(self, key: str, default: Any = None) -> Any:
38+
"""Get a configuration value by key.
39+
40+
Args:
41+
key: Configuration key
42+
default: Default value if key not found
43+
44+
Returns:
45+
Configuration value or default
46+
"""
47+
return self._config.get(key, default)
48+
49+
def set(self, key: str, value: Any) -> None:
50+
"""Set a configuration value.
51+
52+
Args:
53+
key: Configuration key
54+
value: Configuration value
55+
"""
56+
self._config.set(key, value)
57+
58+
def update(self, config_dict: dict[str, Any]) -> None:
59+
"""Update configuration with values from a dictionary.
60+
61+
Args:
62+
config_dict: Dictionary of configuration values to update
63+
"""
64+
self._config.update(config_dict)
65+
66+
def load_file(self, file_path: str) -> dict[str, Any]:
67+
"""Load configuration from a file.
68+
69+
Args:
70+
file_path: Path to configuration file
71+
72+
Returns:
73+
Dictionary containing loaded configuration
74+
75+
Raises:
76+
ConfigFileError: If file cannot be loaded
77+
"""
78+
return load_config_file(file_path)
79+
80+
def apply_file(
81+
self,
82+
config_path: str | None = None,
83+
search_paths: list[str] | None = None,
84+
file_names: list[str] | None = None,
85+
) -> bool:
86+
"""Load and apply configuration from a file.
87+
88+
Args:
89+
config_path: Explicit path to config file
90+
search_paths: List of directories to search
91+
file_names: List of file names to search for
92+
93+
Returns:
94+
True if configuration was loaded and applied, False otherwise
95+
"""
96+
return apply_config_file(
97+
config_path=config_path,
98+
search_paths=search_paths,
99+
file_names=file_names,
100+
)
101+
102+
def get_schema(self) -> dict[str, Any]:
103+
"""Get the JSON schema for configuration validation.
104+
105+
Returns:
106+
JSON schema dictionary
107+
"""
108+
return get_config_schema()
109+
110+
111+
# Global instance for convenience (acts as the mediator)
112+
config_mediator: ConfigPort = ConfigAdapter()
113+

0 commit comments

Comments
 (0)