mcp-proxy-adapter 6.3.30__py3-none-any.whl → 6.4.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -64,15 +64,25 @@ class UnifiedSecurityMiddleware(BaseHTTPMiddleware):
64
64
  # Create security integration
65
65
  try:
66
66
  security_config = config.get("security", {})
67
- self.security_integration = create_security_integration(security_config)
68
- # Use framework's FastAPI middleware
69
- self.framework_middleware = (
70
- self.security_integration.security_manager.create_fastapi_middleware()
71
- )
72
- logger.info("Using mcp_security_framework FastAPI middleware")
73
- # IMPORTANT: Don't replace self.app! This breaks the middleware chain.
74
- # Instead, store the framework middleware for use in dispatch method.
75
- logger.info("Framework middleware will be used in dispatch method")
67
+
68
+ # Check if permissions are enabled - only use mcp_security_framework if needed
69
+ permissions_config = security_config.get("permissions", {})
70
+ permissions_enabled = permissions_config.get("enabled", False)
71
+
72
+ if permissions_enabled:
73
+ self.security_integration = create_security_integration(security_config)
74
+ # Use framework's FastAPI middleware
75
+ self.framework_middleware = (
76
+ self.security_integration.security_manager.create_fastapi_middleware()
77
+ )
78
+ logger.info("Using mcp_security_framework FastAPI middleware")
79
+ # IMPORTANT: Don't replace self.app! This breaks the middleware chain.
80
+ # Instead, store the framework middleware for use in dispatch method.
81
+ logger.info("Framework middleware will be used in dispatch method")
82
+ else:
83
+ logger.info("Permissions disabled, skipping mcp_security_framework integration")
84
+ self.security_integration = None
85
+ self.framework_middleware = None
76
86
  except Exception as e:
77
87
  logger.error(f"Security framework integration failed: {e}")
78
88
  # Instead of raising error, log warning and continue without security
@@ -53,69 +53,68 @@ class UserInfoMiddleware(BaseHTTPMiddleware):
53
53
  try:
54
54
  # Get API keys configuration
55
55
  security_config = config.get("security", {})
56
- auth_config = security_config.get("auth", {})
57
- permissions_config = security_config.get("permissions", {})
58
-
59
- # Check if permissions are enabled
60
- permissions_enabled = permissions_config.get("enabled", False)
61
-
62
- # Create AuthConfig for mcp_security_framework
63
- mcp_auth_config = AuthConfig(
64
- enabled=True,
65
- methods=["api_key"],
66
- api_keys=auth_config.get("api_keys", {}),
67
- )
68
-
69
- # Initialize PermissionManager only if permissions are enabled
70
- if permissions_enabled:
71
- # Create PermissionConfig for mcp_security_framework
72
- roles_file = permissions_config.get("roles_file")
73
- if roles_file is None:
74
- logger.warning("⚠️ Permissions enabled but no roles_file specified, using default configuration")
75
- roles_file = None
76
-
77
- mcp_permission_config = PermissionConfig(
78
- roles_file=roles_file,
79
- default_role=permissions_config.get("default_role", "guest"),
80
- admin_role=permissions_config.get("admin_role", "admin"),
81
- role_hierarchy=permissions_config.get("role_hierarchy", {}),
82
- permission_cache_enabled=permissions_config.get(
83
- "permission_cache_enabled", True
84
- ),
85
- permission_cache_ttl=permissions_config.get(
86
- "permission_cache_ttl", 300
87
- ),
88
- wildcard_permissions=permissions_config.get(
89
- "wildcard_permissions", False
90
- ),
91
- strict_mode=permissions_config.get("strict_mode", True),
92
- roles=permissions_config.get("roles", {}),
93
- )
94
-
95
- # Initialize PermissionManager first
96
- self.permission_manager = PermissionManager(mcp_permission_config)
56
+
57
+ # Check if security is enabled
58
+ security_enabled = security_config.get("enabled", False)
59
+ if not security_enabled:
60
+ logger.info("ℹ️ Security disabled in configuration, using basic auth")
61
+ self._security_available = False
97
62
  else:
98
- # Create a minimal PermissionManager when permissions are disabled
99
- mcp_permission_config = PermissionConfig(
100
- roles_file=None,
101
- default_role="guest",
102
- admin_role="admin",
103
- role_hierarchy={},
104
- permission_cache_enabled=False,
105
- permission_cache_ttl=300,
106
- wildcard_permissions=False,
107
- strict_mode=False,
108
- roles={},
109
- )
110
- self.permission_manager = PermissionManager(mcp_permission_config)
111
-
112
- # Initialize AuthManager with permission_manager
113
- self.auth_manager = AuthManager(
114
- mcp_auth_config, self.permission_manager
115
- )
116
- logger.info(
117
- "✅ User info middleware initialized with " "mcp_security_framework"
118
- )
63
+ auth_config = security_config.get("auth", {})
64
+ permissions_config = security_config.get("permissions", {})
65
+
66
+ # Check if permissions are enabled
67
+ permissions_enabled = permissions_config.get("enabled", False)
68
+
69
+ # Only use mcp_security_framework if permissions are enabled
70
+ if permissions_enabled:
71
+ # Create AuthConfig for mcp_security_framework
72
+ mcp_auth_config = AuthConfig(
73
+ enabled=True,
74
+ methods=["api_key"],
75
+ api_keys=auth_config.get("api_keys", {}),
76
+ )
77
+
78
+ # Create PermissionConfig for mcp_security_framework
79
+ roles_file = permissions_config.get("roles_file")
80
+ if roles_file is None:
81
+ logger.warning("⚠️ Permissions enabled but no roles_file specified, using default configuration")
82
+ roles_file = None
83
+
84
+ mcp_permission_config = PermissionConfig(
85
+ roles_file=roles_file,
86
+ default_role=permissions_config.get("default_role", "guest"),
87
+ admin_role=permissions_config.get("admin_role", "admin"),
88
+ role_hierarchy=permissions_config.get("role_hierarchy", {}),
89
+ permission_cache_enabled=permissions_config.get(
90
+ "permission_cache_enabled", True
91
+ ),
92
+ permission_cache_ttl=permissions_config.get(
93
+ "permission_cache_ttl", 300
94
+ ),
95
+ wildcard_permissions=permissions_config.get(
96
+ "wildcard_permissions", False
97
+ ),
98
+ strict_mode=permissions_config.get("strict_mode", True),
99
+ roles=permissions_config.get("roles", {}),
100
+ )
101
+
102
+ # Initialize PermissionManager first
103
+ self.permission_manager = PermissionManager(mcp_permission_config)
104
+
105
+ # Initialize AuthManager with permission_manager
106
+ self.auth_manager = AuthManager(
107
+ mcp_auth_config, self.permission_manager
108
+ )
109
+ logger.info(
110
+ "✅ User info middleware initialized with " "mcp_security_framework"
111
+ )
112
+ else:
113
+ # When permissions are disabled, use basic auth without mcp_security_framework
114
+ logger.info("ℹ️ Permissions disabled, using basic token auth without mcp_security_framework")
115
+ self._security_available = False
116
+ # Initialize api_keys for basic auth
117
+ self.api_keys = auth_config.get("api_keys", {})
119
118
  except Exception as e:
120
119
  logger.warning(f"⚠️ Failed to initialize AuthManager: {e}")
121
120
  self._security_available = False
@@ -3,15 +3,26 @@ Dependency management system for remote plugins.
3
3
 
4
4
  This module handles automatic installation and verification of plugin dependencies
5
5
  using pip and other package management tools.
6
+
7
+ Author: Vasiliy Zdanovskiy
8
+ email: vasilyvz@gmail.com
6
9
  """
7
10
 
8
11
  import subprocess
9
12
  import sys
10
13
  import importlib
11
- import pkg_resources
12
- from typing import List, Dict, Any, Optional, Tuple
14
+ from typing import List, Dict, Any, Tuple
13
15
  from pathlib import Path
14
16
 
17
+ try: # Python 3.8+
18
+ from importlib import metadata as importlib_metadata # type: ignore
19
+ except Exception: # pragma: no cover - very old Python fallback
20
+ import importlib_metadata # type: ignore
21
+
22
+ from packaging.requirements import Requirement
23
+ from packaging.specifiers import SpecifierSet
24
+ from packaging.version import Version, InvalidVersion
25
+
15
26
  from mcp_proxy_adapter.core.logging import logger
16
27
 
17
28
 
@@ -28,9 +39,15 @@ class DependencyManager:
28
39
  def _load_installed_packages(self) -> None:
29
40
  """Load list of currently installed packages."""
30
41
  try:
31
- installed = pkg_resources.working_set
32
- for dist in installed:
33
- self._installed_packages[dist.project_name.lower()] = dist.version
42
+ self._installed_packages.clear()
43
+ for dist in importlib_metadata.distributions():
44
+ try:
45
+ name = dist.metadata.get("Name") or dist.metadata.get("name")
46
+ version = dist.version
47
+ if name and version:
48
+ self._installed_packages[name.lower()] = version
49
+ except Exception:
50
+ continue
34
51
  except Exception as e:
35
52
  logger.warning(f"Failed to load installed packages: {e}")
36
53
 
@@ -71,32 +88,32 @@ class DependencyManager:
71
88
  Returns:
72
89
  True if dependency is satisfied, False otherwise
73
90
  """
74
- # Try to import the module
91
+ # Parse requirement (handles version specifiers)
75
92
  try:
76
- importlib.import_module(dependency)
77
- return True
78
- except ImportError:
79
- pass
93
+ req = Requirement(dependency)
94
+ except Exception:
95
+ # Fallback: treat as importable module name
96
+ try:
97
+ importlib.import_module(dependency)
98
+ return True
99
+ except ImportError:
100
+ return False
80
101
 
81
- # Check if it's installed as a package
102
+ # Check installation by distribution name
82
103
  try:
83
- pkg_resources.require(dependency)
84
- return True
85
- except (pkg_resources.DistributionNotFound, pkg_resources.VersionConflict):
86
- pass
104
+ installed_version = importlib_metadata.version(req.name)
105
+ except importlib_metadata.PackageNotFoundError:
106
+ return False
87
107
 
88
- # Check installed packages cache
89
- dep_name = (
90
- dependency.split("==")[0]
91
- .split(">=")[0]
92
- .split("<=")[0]
93
- .split("!=")[0]
94
- .split("~=")[0]
95
- )
96
- if dep_name.lower() in self._installed_packages:
108
+ # If no specifier, any installed version satisfies
109
+ if not req.specifier:
97
110
  return True
98
111
 
99
- return False
112
+ try:
113
+ return Version(installed_version) in req.specifier
114
+ except InvalidVersion:
115
+ # If version parsing fails, fallback to string comparison via specifier
116
+ return req.specifier.contains(installed_version, prereleases=True)
100
117
 
101
118
  def install_dependencies(
102
119
  self, dependencies: List[str], user_install: bool = False
@@ -216,7 +233,7 @@ class DependencyManager:
216
233
  Returns:
217
234
  Dictionary with dependency information
218
235
  """
219
- info = {
236
+ info: Dict[str, Any] = {
220
237
  "name": dependency,
221
238
  "installed": False,
222
239
  "version": None,
@@ -225,10 +242,10 @@ class DependencyManager:
225
242
 
226
243
  # Check if it's installed
227
244
  try:
228
- dist = pkg_resources.get_distribution(dependency)
245
+ version = importlib_metadata.version(dependency)
229
246
  info["installed"] = True
230
- info["version"] = dist.version
231
- except pkg_resources.DistributionNotFound:
247
+ info["version"] = version
248
+ except importlib_metadata.PackageNotFoundError:
232
249
  pass
233
250
 
234
251
  # Check if it's importable
@@ -0,0 +1,21 @@
1
+ {
2
+ "roles": {
3
+ "admin": {
4
+ "permissions": ["*"],
5
+ "description": "Administrator with full access"
6
+ },
7
+ "user": {
8
+ "permissions": ["read", "write"],
9
+ "description": "Regular user with read/write access"
10
+ },
11
+ "readonly": {
12
+ "permissions": ["read"],
13
+ "description": "Read-only user"
14
+ }
15
+ },
16
+ "user_roles": {
17
+ "admin": "admin",
18
+ "user": "user",
19
+ "readonly": "readonly"
20
+ }
21
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "roles": {
3
+ "admin": {
4
+ "permissions": ["*"],
5
+ "description": "Administrator with full access"
6
+ },
7
+ "user": {
8
+ "permissions": ["read", "write"],
9
+ "description": "Regular user with read/write access"
10
+ },
11
+ "readonly": {
12
+ "permissions": ["read"],
13
+ "description": "Read-only user"
14
+ }
15
+ },
16
+ "user_roles": {
17
+ "admin": "admin",
18
+ "user": "user",
19
+ "readonly": "readonly"
20
+ }
21
+ }
@@ -0,0 +1,177 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Author: Vasiliy Zdanovskiy
4
+ email: vasilyvz@gmail.com
5
+ Script for generating comprehensive HTTP configuration for MCP Proxy Adapter.
6
+ Generates single comprehensive configuration with all features enabled.
7
+ """
8
+ import json
9
+ import os
10
+ import argparse
11
+ import uuid
12
+ from typing import Dict, Any
13
+
14
+
15
+ def generate_comprehensive_http_config(
16
+ port: int = 20001,
17
+ roles_file: str = "configs/roles.json",
18
+ ) -> Dict[str, Any]:
19
+ """Generate comprehensive HTTP configuration with all features."""
20
+ return {
21
+ "uuid": str(uuid.uuid4()),
22
+ "server": {
23
+ "host": "127.0.0.1",
24
+ "port": port,
25
+ "debug": False,
26
+ "log_level": "INFO",
27
+ "workers": 1,
28
+ "reload": False
29
+ },
30
+ "ssl": {
31
+ "enabled": False
32
+ },
33
+ "security": {
34
+ "enabled": True,
35
+ "auth": {
36
+ "enabled": True,
37
+ "methods": [
38
+ "api_key"
39
+ ],
40
+ "api_keys": {
41
+ "admin-token-123": "admin",
42
+ "user-token-456": "user",
43
+ "readonly-token-789": "readonly",
44
+ "guest-token-abc": "guest",
45
+ "proxy-token-def": "proxy"
46
+ }
47
+ },
48
+ "permissions": {
49
+ "enabled": True,
50
+ "roles_file": roles_file
51
+ }
52
+ },
53
+ "registration": {
54
+ "enabled": True,
55
+ "url": "http://127.0.0.1:3004/proxy",
56
+ "name": "comprehensive_http_adapter",
57
+ "capabilities": [
58
+ "http",
59
+ "token_auth",
60
+ "roles",
61
+ "registration",
62
+ "heartbeat"
63
+ ],
64
+ "retry_count": 3,
65
+ "retry_delay": 5,
66
+ "heartbeat": {
67
+ "enabled": True,
68
+ "interval": 30
69
+ }
70
+ },
71
+ "protocols": {
72
+ "enabled": True,
73
+ "allowed_protocols": [
74
+ "http"
75
+ ]
76
+ }
77
+ }
78
+
79
+
80
+ def generate_roles_config() -> Dict[str, Any]:
81
+ """Generate comprehensive roles configuration."""
82
+ return {
83
+ "admin": {
84
+ "description": "Full administrative access",
85
+ "permissions": [
86
+ "read",
87
+ "write",
88
+ "execute",
89
+ "delete",
90
+ "admin"
91
+ ],
92
+ "inherits": []
93
+ },
94
+ "user": {
95
+ "description": "Standard user access",
96
+ "permissions": [
97
+ "read",
98
+ "write",
99
+ "execute"
100
+ ],
101
+ "inherits": []
102
+ },
103
+ "readonly": {
104
+ "description": "Read-only access",
105
+ "permissions": [
106
+ "read"
107
+ ],
108
+ "inherits": []
109
+ },
110
+ "guest": {
111
+ "description": "Limited guest access",
112
+ "permissions": [
113
+ "read"
114
+ ],
115
+ "inherits": []
116
+ },
117
+ "proxy": {
118
+ "description": "Proxy registration access",
119
+ "permissions": [
120
+ "read",
121
+ "register",
122
+ "heartbeat"
123
+ ],
124
+ "inherits": []
125
+ }
126
+ }
127
+
128
+
129
+ def main():
130
+ """Generate comprehensive configuration."""
131
+ parser = argparse.ArgumentParser(description="Generate comprehensive HTTP configuration")
132
+ parser.add_argument(
133
+ "--output-dir",
134
+ default="configs",
135
+ help="Output directory for configuration files"
136
+ )
137
+ parser.add_argument(
138
+ "--port",
139
+ type=int,
140
+ default=20001,
141
+ help="Server port"
142
+ )
143
+
144
+ args = parser.parse_args()
145
+
146
+ # Create output directory
147
+ os.makedirs(args.output_dir, exist_ok=True)
148
+
149
+ # Generate comprehensive HTTP configuration
150
+ config = generate_comprehensive_http_config(port=args.port)
151
+ config_file = os.path.join(args.output_dir, "comprehensive_http.json")
152
+
153
+ with open(config_file, 'w') as f:
154
+ json.dump(config, f, indent=2)
155
+
156
+ print(f"Generated: {config_file}")
157
+
158
+ # Generate roles configuration
159
+ roles = generate_roles_config()
160
+ roles_file = os.path.join(args.output_dir, "roles.json")
161
+
162
+ with open(roles_file, 'w') as f:
163
+ json.dump(roles, f, indent=2)
164
+
165
+ print(f"Generated: {roles_file}")
166
+
167
+ print(f"\nGenerated comprehensive configuration in {args.output_dir}/")
168
+ print("Configuration includes:")
169
+ print("- HTTP server with token authentication")
170
+ print("- Role-based permissions")
171
+ print("- Proxy registration")
172
+ print("- Heartbeat monitoring")
173
+ print("- 5 predefined tokens with roles")
174
+
175
+
176
+ if __name__ == "__main__":
177
+ main()
@@ -8,6 +8,7 @@ Generates 6 different configuration types for testing various security scenarios
8
8
  import json
9
9
  import os
10
10
  import argparse
11
+ import uuid
11
12
  from typing import Dict, Any
12
13
 
13
14
 
@@ -16,6 +17,7 @@ def generate_http_simple_config(
16
17
  ) -> Dict[str, Any]:
17
18
  """Generate HTTP configuration without authorization."""
18
19
  return {
20
+ "uuid": str(uuid.uuid4()),
19
21
  "server": {"host": "127.0.0.1", "port": port},
20
22
  "ssl": {"enabled": False},
21
23
  "security": {"enabled": False},
@@ -47,6 +49,7 @@ def generate_http_token_config(
47
49
  ) -> Dict[str, Any]:
48
50
  """Generate HTTP configuration with token authorization."""
49
51
  return {
52
+ "uuid": str(uuid.uuid4()),
50
53
  "server": {"host": "127.0.0.1", "port": port},
51
54
  "ssl": {"enabled": False},
52
55
  "security": {
@@ -83,6 +86,7 @@ def generate_https_simple_config(
83
86
  ) -> Dict[str, Any]:
84
87
  """Generate HTTPS configuration without client certificate verification and authorization."""
85
88
  return {
89
+ "uuid": str(uuid.uuid4()),
86
90
  "server": {"host": "127.0.0.1", "port": port},
87
91
  "ssl": {
88
92
  "enabled": True,
@@ -108,6 +112,7 @@ def generate_https_token_config(
108
112
  ) -> Dict[str, Any]:
109
113
  """Generate HTTPS configuration without client certificate verification with token authorization."""
110
114
  return {
115
+ "uuid": str(uuid.uuid4()),
111
116
  "server": {"host": "127.0.0.1", "port": port},
112
117
  "ssl": {
113
118
  "enabled": True,
@@ -147,12 +152,15 @@ def generate_mtls_no_roles_config(
147
152
  ) -> Dict[str, Any]:
148
153
  """Generate mTLS configuration without roles."""
149
154
  return {
155
+ "uuid": str(uuid.uuid4()),
150
156
  "server": {"host": "127.0.0.1", "port": port},
151
157
  "ssl": {
152
158
  "enabled": True,
153
159
  "cert_file": f"{certs_dir}/localhost_server.crt",
154
160
  "key_file": f"{keys_dir}/localhost_server.key",
155
161
  "ca_cert": f"{certs_dir}/mcp_proxy_adapter_ca_ca.crt",
162
+ "client_cert_file": f"{certs_dir}/admin_cert.pem",
163
+ "client_key_file": f"{certs_dir}/admin_key.pem",
156
164
  "verify_client": True,
157
165
  "client_cert_required": True,
158
166
  },
@@ -174,12 +182,15 @@ def generate_mtls_with_roles_config(
174
182
  ) -> Dict[str, Any]:
175
183
  """Generate mTLS configuration with roles."""
176
184
  return {
185
+ "uuid": str(uuid.uuid4()),
177
186
  "server": {"host": "127.0.0.1", "port": port},
178
187
  "ssl": {
179
188
  "enabled": True,
180
189
  "cert_file": f"{certs_dir}/localhost_server.crt",
181
190
  "key_file": f"{keys_dir}/localhost_server.key",
182
191
  "ca_cert": f"{certs_dir}/mcp_proxy_adapter_ca_ca.crt",
192
+ "client_cert_file": f"{certs_dir}/admin_cert.pem",
193
+ "client_key_file": f"{certs_dir}/admin_key.pem",
183
194
  "verify_client": True,
184
195
  },
185
196
  "registration": {
@@ -618,135 +618,66 @@ def generate_enhanced_configurations(output_dir: Path) -> None:
618
618
 
619
619
  validator = ConfigurationValidator()
620
620
 
621
- # Configuration templates with proper protocol settings
621
+ # Single comprehensive HTTP configuration with all features
622
622
  configs = {
623
- "development_http.json": {
624
- "server": {"host": "0.0.0.0", "port": 8000},
625
- "protocols": {"enabled": False},
626
- "security": {"ssl": {"enabled": False}},
627
- "logging": {"level": "DEBUG"},
628
- },
629
- "production_https.json": {
630
- "uuid": "550e8400-e29b-41d4-a716-446655440001",
631
- "server": {"host": "0.0.0.0", "port": 8443},
632
- "protocols": {"enabled": True, "allowed_protocols": ["https"]},
633
- "ssl": {
634
- "enabled": True,
635
- "cert_file": "mcp_proxy_adapter/examples/basic_framework/certs/server_cert.pem",
636
- "key_file": "mcp_proxy_adapter/examples/basic_framework/certs/server_key.pem",
637
- "ca_cert_file": "mcp_proxy_adapter/examples/basic_framework/certs/ca_cert.pem",
638
- "verify_client": False,
639
- "min_tls_version": "TLSv1.2",
640
- },
641
- "logging": {"level": "INFO"},
642
- },
643
- "mtls_with_roles.json": {
623
+ "comprehensive_http.json": {
644
624
  "uuid": "550e8400-e29b-41d4-a716-446655440000",
645
- "server": {"host": "0.0.0.0", "port": 8443},
646
- "protocols": {"enabled": True, "allowed_protocols": ["https", "mtls"]},
625
+ "server": {
626
+ "host": "127.0.0.1",
627
+ "port": 20001,
628
+ "debug": False,
629
+ "log_level": "INFO",
630
+ "workers": 1,
631
+ "reload": False
632
+ },
647
633
  "ssl": {
648
- "enabled": True,
649
- "cert_file": "mcp_proxy_adapter/examples/basic_framework/certs/server_cert.pem",
650
- "key_file": "mcp_proxy_adapter/examples/basic_framework/certs/server_key.pem",
651
- "ca_cert_file": "mcp_proxy_adapter/examples/basic_framework/certs/ca_cert.pem",
652
- "verify_client": True,
653
- "min_tls_version": "TLSv1.2",
634
+ "enabled": False
654
635
  },
655
636
  "security": {
637
+ "enabled": True,
656
638
  "auth": {
657
639
  "enabled": True,
658
- "token_required": False,
659
- "token_secret": "your-secret-key",
640
+ "methods": [
641
+ "api_key"
642
+ ],
643
+ "api_keys": {
644
+ "admin-token-123": "admin",
645
+ "user-token-456": "user",
646
+ "readonly-token-789": "readonly",
647
+ "guest-token-abc": "guest",
648
+ "proxy-token-def": "proxy"
649
+ }
660
650
  },
661
- },
662
- "logging": {"level": "INFO"},
663
- },
664
- "mtls_no_roles.json": {
665
- "server": {"host": "0.0.0.0", "port": 8443},
666
- "protocols": {"enabled": True, "allowed_protocols": ["https", "mtls"]},
667
- "security": {
668
- "ssl": {
651
+ "permissions": {
669
652
  "enabled": True,
670
- "server_cert_file": "certs/server_cert.pem",
671
- "server_key_file": "keys/server_key.pem",
672
- "ca_cert_file": "certs/ca_cert.pem",
673
- "client_cert_file": "certs/client_cert.pem",
674
- "client_key_file": "keys/client_key.pem",
675
- "verify_server": True,
676
- "verify_client": True,
677
- "min_tls_version": "TLSv1.2",
653
+ "roles_file": "configs/roles.json"
678
654
  }
679
655
  },
680
- "logging": {"level": "INFO"},
681
- },
682
- "https_simple.json": {
683
- "uuid": "550e8400-e29b-41d4-a716-446655440002",
684
- "server": {"host": "0.0.0.0", "port": 8443},
685
- "protocols": {"enabled": True, "allowed_protocols": ["https"]},
686
- "ssl": {
656
+ "registration": {
687
657
  "enabled": True,
688
- "cert_file": "mcp_proxy_adapter/examples/basic_framework/certs/server_cert.pem",
689
- "key_file": "mcp_proxy_adapter/examples/basic_framework/certs/server_key.pem",
690
- "verify_client": False,
691
- "min_tls_version": "TLSv1.2",
692
- },
693
- "logging": {"level": "INFO"},
694
- },
695
- "https_with_auth.json": {
696
- "server": {"host": "0.0.0.0", "port": 8443},
697
- "protocols": {"enabled": True, "allowed_protocols": ["https"]},
698
- "security": {
699
- "ssl": {
700
- "enabled": True,
701
- "server_cert_file": "certs/server_cert.pem",
702
- "server_key_file": "keys/server_key.pem",
703
- "verify_server": True,
704
- "ca_cert_file": "certs/ca_cert.pem",
705
- "verify_client": False,
706
- "min_tls_version": "TLSv1.2",
707
- },
708
- "auth": {
709
- "enabled": True,
710
- "token_required": True,
711
- "token_secret": "your-secret-key",
712
- },
713
- },
714
- "logging": {"level": "INFO"},
715
- },
716
- "test_proxy_registration.json": {
717
- "server": {"host": "127.0.0.1", "port": 8010},
718
- "protocols": {"enabled": True, "allowed_protocols": ["https", "mtls"]},
719
- "security": {
720
- "ssl": {
658
+ "url": "http://127.0.0.1:3004/proxy",
659
+ "name": "comprehensive_http_adapter",
660
+ "capabilities": [
661
+ "http",
662
+ "token_auth",
663
+ "roles",
664
+ "registration",
665
+ "heartbeat"
666
+ ],
667
+ "retry_count": 3,
668
+ "retry_delay": 5,
669
+ "heartbeat": {
721
670
  "enabled": True,
722
- "server_cert_file": "certs/mtls/server/embedding-service.pem",
723
- "server_key_file": "certs/mtls/server/embedding-service.key",
724
- "ca_cert_file": "certs/mtls/truststore.pem",
725
- "client_cert_file": "certs/mtls/client/embedding-service.pem",
726
- "client_key_file": "certs/mtls/client/embedding-service.key",
727
- "verify_server": True,
728
- "verify_client": True,
729
- "min_tls_version": "TLSv1.2",
671
+ "interval": 30
730
672
  }
731
673
  },
732
- "registration": {
674
+ "protocols": {
733
675
  "enabled": True,
734
- "proxy_url": "https://127.0.0.1:3004",
735
- "server_id": "test-proxy-registration",
736
- "server_name": "Test Proxy Registration Service",
737
- "description": "Test service for proxy registration SSL fix",
738
- "auth_method": "certificate",
739
- "certificate": {
740
- "cert_file": "certs/mtls/client/embedding-service.pem",
741
- "key_file": "certs/mtls/client/embedding-service.key",
742
- },
743
- "ssl": {
744
- "verify_mode": "CERT_REQUIRED",
745
- "ca_cert": "mtls_certificates/truststore.pem",
746
- },
747
- },
748
- "logging": {"level": "DEBUG"},
749
- },
676
+ "allowed_protocols": [
677
+ "http"
678
+ ]
679
+ }
680
+ }
750
681
  }
751
682
 
752
683
  # Generate and validate configurations
@@ -777,41 +708,81 @@ def generate_enhanced_configurations(output_dir: Path) -> None:
777
708
  index_path = configs_dir / "README.md"
778
709
  with open(index_path, "w", encoding="utf-8") as f:
779
710
  f.write(
780
- """# Configuration Files
711
+ """# Comprehensive HTTP Configuration
712
+
713
+ This directory contains a single comprehensive HTTP configuration with all features enabled.
714
+
715
+ ## Available Configuration
781
716
 
782
- This directory contains pre-configured examples for different deployment scenarios.
717
+ ### Comprehensive HTTP
718
+ - `comprehensive_http.json` - Complete HTTP server with all features
783
719
 
784
- ## Available Configurations
720
+ ## Features
785
721
 
786
- ### Development
787
- - `development_http.json` - HTTP development server (no SSL)
722
+ ### Security
723
+ - **Token Authentication**: API key-based access control with 5 predefined tokens
724
+ - **Role-based Permissions**: Granular access control with 5 roles
725
+ - **Roles**: admin, user, readonly, guest, proxy
788
726
 
789
- ### Production HTTPS
790
- - `production_https.json` - HTTPS with server certificate verification
791
- - `https_simple.json` - HTTPS without certificate verification
792
- - `https_with_auth.json` - HTTPS with token authentication
727
+ ### Authentication Tokens
728
+ - `admin-token-123` admin role (full access)
729
+ - `user-token-456` user role (read, write, execute)
730
+ - `readonly-token-789` readonly role (read only)
731
+ - `guest-token-abc` → guest role (limited access)
732
+ - `proxy-token-def` → proxy role (registration, heartbeat)
793
733
 
794
- ### mTLS (Mutual TLS)
795
- - `mtls_with_roles.json` - mTLS with role-based authentication
796
- - `mtls_no_roles.json` - mTLS without roles
734
+ ### Registration & Monitoring
735
+ - **Proxy Registration**: Automatic service discovery
736
+ - **Heartbeat**: 30-second health monitoring
737
+ - **Retry Logic**: 3 attempts with 5-second delay
738
+
739
+ ### Protocols
740
+ - **HTTP**: Standard web protocol (port 20001)
797
741
 
798
742
  ## Usage
799
743
 
800
- Start the server with a specific configuration:
744
+ ### Starting the Server
745
+ ```bash
746
+ # Start comprehensive HTTP server
747
+ python -m mcp_proxy_adapter --config configs/comprehensive_http.json
748
+ ```
801
749
 
750
+ ### Testing Authentication
802
751
  ```bash
803
- python -m mcp_proxy_adapter --config configs/production_https.json
752
+ # Test with admin token
753
+ curl -H "Authorization: Bearer admin-token-123" http://localhost:20001/health
754
+
755
+ # Test with user token
756
+ curl -H "Authorization: Bearer user-token-456" http://localhost:20001/health
757
+
758
+ # Test with readonly token
759
+ curl -H "Authorization: Bearer readonly-token-789" http://localhost:20001/health
804
760
  ```
805
761
 
806
- ## Validation
762
+ ## Configuration Details
807
763
 
808
- All configurations are validated for:
809
- - Mutually exclusive settings
810
- - Required dependencies
811
- - Protocol compatibility
812
- - Security best practices
764
+ - **Server**: 127.0.0.1:20001
765
+ - **SSL**: Disabled (HTTP only)
766
+ - **Authentication**: Token-based with roles
767
+ - **Registration**: Enabled with proxy server
768
+ - **Heartbeat**: 30-second interval
769
+ - **Protocols**: HTTP only
770
+
771
+ ## Customization
772
+
773
+ Edit `comprehensive_http.json` to:
774
+ - Change server host/port
775
+ - Add/modify authentication tokens
776
+ - Update role permissions
777
+ - Modify registration settings
778
+ - Adjust heartbeat interval
779
+
780
+ ## Troubleshooting
813
781
 
814
- See `docs/CONFIGURATION_GUIDE.md` for detailed documentation.
782
+ 1. **Port Conflicts**: Ensure port 20001 is not in use
783
+ 2. **Token Issues**: Verify token format and role mapping
784
+ 3. **Registration Issues**: Check proxy server availability
785
+ 4. **Permission Errors**: Verify roles.json file exists
815
786
  """
816
787
  )
817
788
 
@@ -2,4 +2,4 @@
2
2
  Version information for MCP Proxy Adapter.
3
3
  """
4
4
 
5
- __version__ = "6.3.30"
5
+ __version__ = "6.3.31"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mcp-proxy-adapter
3
- Version: 6.3.30
3
+ Version: 6.4.1
4
4
  Summary: Powerful JSON-RPC microservices framework with built-in security, authentication, and proxy registration
5
5
  Home-page: https://github.com/maverikod/mcp-proxy-adapter
6
6
  Author: Vasiliy Zdanovskiy
@@ -4,7 +4,7 @@ mcp_proxy_adapter/config.py,sha256=-7iVS0mUWWKNeao7nqTAFlUD6FcMwRlDkchN7OwYsr0,2
4
4
  mcp_proxy_adapter/custom_openapi.py,sha256=yLle4CntYK9wpivgn9NflZyJhy-YNrmWjJzt0ai5nP0,14672
5
5
  mcp_proxy_adapter/main.py,sha256=idp3KUR7CT7kTXLVPvvclJlNnt8d_HYl8_jY98uknmo,4677
6
6
  mcp_proxy_adapter/openapi.py,sha256=2UZOI09ZDRJuBYBjKbMyb2U4uASszoCMD5o_4ktRpvg,13480
7
- mcp_proxy_adapter/version.py,sha256=P9yxGAMLjCfxwoZms2TyoWvVR_JhmPQJrS3y9M1gBlw,75
7
+ mcp_proxy_adapter/version.py,sha256=P9qw3X3vfbgoqSgoCae8MiE-WtXOwkrl5G370CizL5E,75
8
8
  mcp_proxy_adapter/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
9
  mcp_proxy_adapter/api/app.py,sha256=dIsAWbQFWMa8zxhPro9hxUnUuqnLWlqutWAKrqJIHGE,33386
10
10
  mcp_proxy_adapter/api/handlers.py,sha256=iyFGoEuUS1wxbV1ELA0zmaxIyQR7j4zw-4MrD-uIO6E,8294
@@ -20,8 +20,8 @@ mcp_proxy_adapter/api/middleware/logging.py,sha256=iME87hrbvyTjI-RJro5Cwao7VlHUI
20
20
  mcp_proxy_adapter/api/middleware/performance.py,sha256=-EvA7YIcTlxn8RuxlWlScJvX2EIoeEp3P5dKVWZHYRY,2357
21
21
  mcp_proxy_adapter/api/middleware/protocol_middleware.py,sha256=YiwgeWXaFjj-TvTpAyqOMu1Rql4UENmX6pAJ8vEb9T8,15449
22
22
  mcp_proxy_adapter/api/middleware/transport_middleware.py,sha256=VG1rWyuh-O2pdc0kQ3SADFvyh286o5Wrnkt8OFQ0WQw,4274
23
- mcp_proxy_adapter/api/middleware/unified_security.py,sha256=PMbJxVzGNlb-IPAqvIeEo1st-jykYX9Mns6lXIfdtAE,7764
24
- mcp_proxy_adapter/api/middleware/user_info_middleware.py,sha256=94oItW3uyNhLvp6p1Sl7EhY_gC4MqrbR9KyAJWreTwk,10326
23
+ mcp_proxy_adapter/api/middleware/unified_security.py,sha256=qjNPOCusMimXjEtjwyG6CgFieLm2T7O2e2QghqE_s3M,8313
24
+ mcp_proxy_adapter/api/middleware/user_info_middleware.py,sha256=sUHHyy33xvZKRDtOWfzbndrIxDYLUFeVYfUbPIKawR8,10652
25
25
  mcp_proxy_adapter/commands/__init__.py,sha256=eStfu2UrLfMvMTY6x20GD8sMPmPB1so-0QZQYV53nqo,1565
26
26
  mcp_proxy_adapter/commands/auth_validation_command.py,sha256=p4UrAaHyoCxMy98G1BUUlFJWjoelEJzX3OAWIiQaGls,14593
27
27
  mcp_proxy_adapter/commands/base.py,sha256=0_hu8t89-2vWBPFpEMokr27A-IifKI32rkQwZfc2Grk,15162
@@ -32,7 +32,7 @@ mcp_proxy_adapter/commands/certificate_management_command.py,sha256=TDoGV2mnEz1H
32
32
  mcp_proxy_adapter/commands/command_registry.py,sha256=RFGZw-0A29P6ZQMZ2qi5wQe3K89hCNOqRTdhtYYDGDg,36498
33
33
  mcp_proxy_adapter/commands/config_command.py,sha256=PWX1OhKAmjlc8CSy4-sImdvGeSNgDNyv30Y-P5iZp9g,3767
34
34
  mcp_proxy_adapter/commands/dependency_container.py,sha256=mvPob62lQ-mKRbAA9aL3L5gOT9_4V2Vy2cGoup2S840,3239
35
- mcp_proxy_adapter/commands/dependency_manager.py,sha256=JWdmQ0de6rQAv8GYDToFIlpomBBXqT61XMygWcggYSQ,7366
35
+ mcp_proxy_adapter/commands/dependency_manager.py,sha256=lXgtrhCiQhy9Y-QpU_RWRg2d0VYy5msoNQPUjPOcOc8,8245
36
36
  mcp_proxy_adapter/commands/echo_command.py,sha256=7E4DGGYULt6XN7NOTHwpmM9rMJgJ-ykMTqImOXY8160,2378
37
37
  mcp_proxy_adapter/commands/health_command.py,sha256=Li0snwkFHdeYdYy4Nrrt_OpLU9cZedfoNatndT_yLUo,4543
38
38
  mcp_proxy_adapter/commands/help_command.py,sha256=y6-li7XLAS_W4forLO-8r4QsnKVqzB2OmQzNKcMZ1f8,14224
@@ -89,7 +89,8 @@ mcp_proxy_adapter/examples/demo_client.py,sha256=en2Rtb70B1sQmhL-vdQ4PDpKNNl_mfl
89
89
  mcp_proxy_adapter/examples/generate_all_certificates.py,sha256=lLP5RKmJwpSyprvrxQXFt_xcN4aiUzlIxk5WVdXx2Fk,19024
90
90
  mcp_proxy_adapter/examples/generate_certificates.py,sha256=VRJnT9Za2Wk_oKRT5g2SA7qcGeBSxZm9wPMOM5i50T0,6707
91
91
  mcp_proxy_adapter/examples/generate_certificates_and_tokens.py,sha256=hUCoJH3fy5WeR_YMHj-_W0mR0ZKUWqewH4FVN3yWyrM,17972
92
- mcp_proxy_adapter/examples/generate_test_configs.py,sha256=hzb9NBCl21Og9Tsox8nRT_uG0AhgT-t7uRyghinucc8,13853
92
+ mcp_proxy_adapter/examples/generate_comprehensive_config.py,sha256=2UyTGIUKxw3EdCFaOMwO1vB-OZjOQV0senU44JPuyH0,4787
93
+ mcp_proxy_adapter/examples/generate_test_configs.py,sha256=RorZOrhjtoFwtC0Y0kQK7wBA1OnvHDod9nK-C2PMgPo,14323
93
94
  mcp_proxy_adapter/examples/proxy_registration_example.py,sha256=vemRhftnjbiOBCJkmtDGqlWQ8syTG0a8755GCOnaQsg,12503
94
95
  mcp_proxy_adapter/examples/run_example.py,sha256=yp-a6HIrSk3ddQmbn0KkuKwErId0aNfj028TE6U-zmY,2626
95
96
  mcp_proxy_adapter/examples/run_full_test_suite.py,sha256=bR25OOrmWnLQccZno9cZhi_Ltk_6k8DFR2vXPCj1XQ4,12468
@@ -97,14 +98,14 @@ mcp_proxy_adapter/examples/run_proxy_server.py,sha256=SBLSSY2F_VEBQD3MsCE_Pa9xFE
97
98
  mcp_proxy_adapter/examples/run_security_tests.py,sha256=0vjaUdWC-rLyviQuNxM3PtfiU9TzSRuxGxWMehrFA_w,23311
98
99
  mcp_proxy_adapter/examples/run_security_tests_fixed.py,sha256=2BKMT0_-FhmcZA73hdQOt2XR7Cgb9Sq8qBI88BkwAAA,10934
99
100
  mcp_proxy_adapter/examples/security_test_client.py,sha256=K5gEVat1SJS2pBVxqLl5c9-uiiG12k8UT3ULQDXZ2Uc,35713
100
- mcp_proxy_adapter/examples/setup_test_environment.py,sha256=FiBC52GfNFzv_U2RK3GnhNLLZeo5UdUNWDaIaG5sZ68,37198
101
- mcp_proxy_adapter/examples/setup_test_environment_old.py,sha256=qV7IT8lMObcaPeNrFXI7CkuvJnbJsLIVaRn7fTFXjJ0,11631
101
+ mcp_proxy_adapter/examples/setup_test_environment.py,sha256=LR4kGneHELgk4lHMfA9k1yFZ1o3KEQelqOXua5oT88Q,34540
102
102
  mcp_proxy_adapter/examples/test_config.py,sha256=ekEoUZe9q484vU_0IxOVhQdNMVJXG3IpmQpP--VmuDI,6491
103
103
  mcp_proxy_adapter/examples/test_config_generator.py,sha256=PBXk1V_awJ-iBlbE66Pme5sQwu6CJDxkmqgm8uPtM58,4091
104
104
  mcp_proxy_adapter/examples/test_examples.py,sha256=CYlVatdHUVC_rwv4NsvxFG3GXiKIyxPDUH43BOJHjrU,12330
105
105
  mcp_proxy_adapter/examples/universal_client.py,sha256=n1-cBPOiCipA86Zcc_mI_jMywDMZS1p3u5JT3AqTsrQ,27577
106
106
  mcp_proxy_adapter/examples/basic_framework/__init__.py,sha256=4aYD--R6hy9n9CUxj7Osb9HcdVUMJ6_cfpu4ujkbCwI,345
107
107
  mcp_proxy_adapter/examples/basic_framework/main.py,sha256=AkGUXW05_AK8SEKwlS_0isJKKqjulKBDPp7t36t9QJk,1787
108
+ mcp_proxy_adapter/examples/basic_framework/roles.json,sha256=I0lSP3hfq1DESv3xsZ7-xOEdzaQGCb8b9YMK_AOPDsE,510
108
109
  mcp_proxy_adapter/examples/basic_framework/commands/__init__.py,sha256=_VQNLUEdsxUG-4yt9BZI_vtOxHAdGG0OUSsP6Wj-Vz4,76
109
110
  mcp_proxy_adapter/examples/basic_framework/hooks/__init__.py,sha256=IE_EIXMnkdXuakZn7wLD9kBFyfDF5lYi56ejgiBeb-A,70
110
111
  mcp_proxy_adapter/examples/commands/__init__.py,sha256=zvY_OpH_B1bVc_khrNIl6O8vqCw1FH6gGMAsJAkGWGY,170
@@ -124,6 +125,7 @@ mcp_proxy_adapter/examples/examples/full_application/hooks/builtin_command_hooks
124
125
  mcp_proxy_adapter/examples/full_application/__init__.py,sha256=xGiPYhRAzs1Fh9wA8HoowV-Gg9QMLaMZn-OamExq1TI,320
125
126
  mcp_proxy_adapter/examples/full_application/main.py,sha256=ogL3Bil_5puGnwvMh3YNOjrW76FIzzoggKEp-04HSfo,7855
126
127
  mcp_proxy_adapter/examples/full_application/proxy_endpoints.py,sha256=Kt_WAsG61HLTMkKQ1mQqjvlX9I4TcfwYq0NaRR9HKvM,6179
128
+ mcp_proxy_adapter/examples/full_application/roles.json,sha256=I0lSP3hfq1DESv3xsZ7-xOEdzaQGCb8b9YMK_AOPDsE,510
127
129
  mcp_proxy_adapter/examples/full_application/commands/__init__.py,sha256=yQHxVSFkAyFLUOdk42QOebUODPlQV9IbydPgF3UKsGM,217
128
130
  mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py,sha256=H7FPJmVJNWT61rPWxep06-7hsYRt8XYBUSBiwqpBurU,3096
129
131
  mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py,sha256=DFTqVnIDt6nBdZ27-vD_f1X2cFcDInVQiCEq9ltw4lA,3428
@@ -137,8 +139,8 @@ mcp_proxy_adapter/schemas/base_schema.json,sha256=v9G9cGMd4dRhCZsOQ_FMqOi5VFyVbI
137
139
  mcp_proxy_adapter/schemas/openapi_schema.json,sha256=C3yLkwmDsvnLW9B5gnKKdBGl4zxkeU-rEmjTrNVsQU0,8405
138
140
  mcp_proxy_adapter/utils/config_generator.py,sha256=UXxuxxAyKTesAS3DOofQ26e20v771inA7EfBV8PZD1c,47543
139
141
  mcp_proxy_adapter_issue_package/demonstrate_issue.py,sha256=O54fwWQvUAjEGiHhQGm1JLnARkhVCwAqjBk_89HyRbY,7894
140
- mcp_proxy_adapter-6.3.30.dist-info/METADATA,sha256=BxBZhz8TcLcDZt3bdhdYHTcpddyQ8dnmizdSnv53fzQ,22404
141
- mcp_proxy_adapter-6.3.30.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
142
- mcp_proxy_adapter-6.3.30.dist-info/entry_points.txt,sha256=J3eV6ID0lt_VSp4lIdIgBFTqLCThgObNNxRCbyfiMHw,70
143
- mcp_proxy_adapter-6.3.30.dist-info/top_level.txt,sha256=CHk-Mc-AxjO-tRheegA2qLiQnU4vZRnxuTF81So6SAc,50
144
- mcp_proxy_adapter-6.3.30.dist-info/RECORD,,
142
+ mcp_proxy_adapter-6.4.1.dist-info/METADATA,sha256=z0V7ZTjQlTXg1cGCGu5NaRbvqQk4Z7moSp3lvLeNgKE,22403
143
+ mcp_proxy_adapter-6.4.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
144
+ mcp_proxy_adapter-6.4.1.dist-info/entry_points.txt,sha256=J3eV6ID0lt_VSp4lIdIgBFTqLCThgObNNxRCbyfiMHw,70
145
+ mcp_proxy_adapter-6.4.1.dist-info/top_level.txt,sha256=CHk-Mc-AxjO-tRheegA2qLiQnU4vZRnxuTF81So6SAc,50
146
+ mcp_proxy_adapter-6.4.1.dist-info/RECORD,,
@@ -1,316 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- Author: Vasiliy Zdanovskiy
4
- email: vasilyvz@gmail.com
5
- Script for setting up test environment for MCP Proxy Adapter.
6
- Prepares the test environment with all necessary files and directories.
7
- Uses mcp_security_framework for certificate generation.
8
-
9
- This script accepts an output directory and copies required example files
10
- and helper scripts into that directory, creating a ready-to-use workspace.
11
- By default, the current working directory is used, so end-users can run
12
- it in their project root after installing this framework in a virtual
13
- environment.
14
- """
15
- import shutil
16
- import sys
17
- import argparse
18
- from pathlib import Path
19
-
20
- # Import mcp_security_framework
21
- try:
22
- from mcp_security_framework.core.cert_manager import CertificateManager
23
- from mcp_security_framework.schemas.config import (
24
- CertificateConfig,
25
- CAConfig,
26
- ServerCertConfig,
27
- ClientCertConfig,
28
- )
29
-
30
- SECURITY_FRAMEWORK_AVAILABLE = True
31
- except ImportError:
32
- SECURITY_FRAMEWORK_AVAILABLE = False
33
- print("Warning: mcp_security_framework not available")
34
-
35
-
36
- def _get_package_paths() -> tuple[Path, Path]:
37
- """
38
- Resolve source paths for examples and utils relative to this file
39
- to avoid importing the package during setup.
40
- """
41
- pkg_root = Path(__file__).resolve().parents[1]
42
- return pkg_root / "examples", pkg_root / "utils"
43
-
44
-
45
- def setup_test_environment(output_dir: Path) -> None:
46
- """
47
- Setup test environment under output_dir with required files
48
- and directories.
49
-
50
- All created directories and copied files are rooted at output_dir
51
- so users can run scripts relative to that directory.
52
- """
53
- print("🔧 Setting up test environment...")
54
- output_dir = output_dir.resolve()
55
- output_dir.mkdir(parents=True, exist_ok=True)
56
- # Create test environment directory structure
57
- directories = [
58
- "examples/basic_framework",
59
- "examples/full_application",
60
- "scripts",
61
- "configs",
62
- "certs",
63
- "keys",
64
- "tokens",
65
- "logs",
66
- ]
67
- for directory in directories:
68
- target_dir = output_dir / directory
69
- target_dir.mkdir(parents=True, exist_ok=True)
70
- print(f"✅ Created directory: {target_dir}")
71
- # Resolve package paths
72
- examples_src_root, utils_src_root = _get_package_paths()
73
- # Copy example files
74
- basic_framework_src = examples_src_root / "basic_framework"
75
- if basic_framework_src.exists():
76
- shutil.copytree(
77
- basic_framework_src,
78
- output_dir / "examples/basic_framework",
79
- dirs_exist_ok=True,
80
- )
81
- print("✅ Copied basic_framework examples")
82
- full_application_src = examples_src_root / "full_application"
83
- if full_application_src.exists():
84
- shutil.copytree(
85
- full_application_src,
86
- output_dir / "examples/full_application",
87
- dirs_exist_ok=True,
88
- )
89
- print("✅ Copied full_application examples")
90
- # Copy utility scripts
91
- config_generator_src = utils_src_root / "config_generator.py"
92
- if config_generator_src.exists():
93
- shutil.copy2(config_generator_src, output_dir / "scripts/")
94
- print("✅ Copied config_generator.py")
95
- # Copy certificate generation scripts
96
- create_certs_src = examples_src_root / "create_certificates_simple.py"
97
- if create_certs_src.exists():
98
- shutil.copy2(create_certs_src, output_dir / "scripts/")
99
- print("✅ Copied create_certificates_simple.py")
100
- cert_tokens_src = examples_src_root / "generate_certificates_and_tokens.py"
101
- if cert_tokens_src.exists():
102
- shutil.copy2(cert_tokens_src, output_dir / "scripts/")
103
- print("✅ Copied generate_certificates_and_tokens.py")
104
-
105
- # Copy roles.json to the root directory for compatibility
106
- roles_src = examples_src_root / "roles.json"
107
- if roles_src.exists():
108
- shutil.copy2(roles_src, output_dir)
109
- print("✅ Copied roles.json to root directory")
110
-
111
- # Also copy from configs directory if it exists
112
- roles_configs_src = output_dir / "configs" / "roles.json"
113
- if roles_configs_src.exists():
114
- shutil.copy2(roles_configs_src, output_dir / "roles.json")
115
- print("✅ Updated roles.json from configs directory")
116
- print("🎉 Test environment setup completed successfully at: {}".format(output_dir))
117
-
118
-
119
- def generate_certificates_with_framework(output_dir: Path) -> bool:
120
- """
121
- Generate certificates using mcp_security_framework.
122
- """
123
- if not SECURITY_FRAMEWORK_AVAILABLE:
124
- print("❌ mcp_security_framework not available for certificate " "generation")
125
- return False
126
- try:
127
- print("🔐 Generating certificates using mcp_security_framework...")
128
- # Configure certificate manager
129
- cert_config = CertificateConfig(
130
- cert_storage_path=str((output_dir / "certs").resolve()),
131
- key_storage_path=str((output_dir / "keys").resolve()),
132
- default_validity_days=365,
133
- key_size=2048,
134
- hash_algorithm="sha256",
135
- )
136
- cert_manager = CertificateManager(cert_config)
137
- # Generate CA certificate
138
- ca_config = CAConfig(
139
- common_name="MCP Proxy Adapter Test CA",
140
- organization="Test Organization",
141
- organizational_unit="Certificate Authority",
142
- country="US",
143
- state="Test State",
144
- locality="Test City",
145
- validity_years=10, # Use validity_years instead of validity_days
146
- key_size=2048,
147
- hash_algorithm="sha256",
148
- )
149
- cert_pair = cert_manager.create_root_ca(ca_config)
150
- if not cert_pair or not cert_pair.certificate_path:
151
- print("❌ Failed to create CA certificate: Invalid certificate pair")
152
- return False
153
- print("✅ CA certificate created successfully")
154
- # Find CA key file
155
- ca_key_path = cert_pair.private_key_path
156
- # Generate server certificate
157
- server_config = ServerCertConfig(
158
- common_name="localhost",
159
- organization="Test Organization",
160
- organizational_unit="Server",
161
- country="US",
162
- state="Test State",
163
- locality="Test City",
164
- validity_days=365,
165
- key_size=2048,
166
- hash_algorithm="sha256",
167
- subject_alt_names=[
168
- "localhost",
169
- "127.0.0.1",
170
- ],
171
- ca_cert_path=cert_pair.certificate_path,
172
- ca_key_path=ca_key_path,
173
- )
174
- cert_pair = cert_manager.create_server_certificate(server_config)
175
- if not cert_pair or not cert_pair.certificate_path:
176
- print("❌ Failed to create server certificate: Invalid certificate " "pair")
177
- return False
178
- print("✅ Server certificate created successfully")
179
- # Generate client certificates
180
- client_configs = [
181
- (
182
- "admin",
183
- ["admin"],
184
- [
185
- "read",
186
- "write",
187
- "execute",
188
- "delete",
189
- "admin",
190
- "register",
191
- "unregister",
192
- "heartbeat",
193
- "discover",
194
- ],
195
- ),
196
- (
197
- "user",
198
- ["user"],
199
- [
200
- "read",
201
- "execute",
202
- "register",
203
- "unregister",
204
- "heartbeat",
205
- "discover",
206
- ],
207
- ),
208
- ("readonly", ["readonly"], ["read", "discover"]),
209
- ("guest", ["guest"], ["read", "discover"]),
210
- (
211
- "proxy",
212
- ["proxy"],
213
- ["register", "unregister", "heartbeat", "discover"],
214
- ),
215
- ]
216
- for client_name, roles, permissions in client_configs:
217
- client_config = ClientCertConfig(
218
- common_name=f"{client_name}-client",
219
- organization="Test Organization",
220
- organizational_unit="Client",
221
- country="US",
222
- state="Test State",
223
- locality="Test City",
224
- validity_days=730,
225
- key_size=2048,
226
- hash_algorithm="sha256",
227
- roles=roles,
228
- permissions=permissions,
229
- ca_cert_path=cert_pair.certificate_path,
230
- ca_key_path=ca_key_path,
231
- )
232
- cert_pair = cert_manager.create_client_certificate(client_config)
233
- if not cert_pair or not cert_pair.certificate_path:
234
- print(
235
- (
236
- "❌ Failed to create client certificate {}: "
237
- "Invalid certificate pair"
238
- ).format(client_name)
239
- )
240
- return False
241
- print("✅ Client certificate {} created successfully".format(client_name))
242
- print(
243
- "🎉 All certificates generated successfully using "
244
- "mcp_security_framework!"
245
- )
246
- return True
247
- except Exception as e:
248
- print("❌ Error generating certificates with framework: {}".format(e))
249
- print("\n🔧 TROUBLESHOOTING:")
250
- print("1. Check if mcp_security_framework is installed:")
251
- print(" pip install mcp_security_framework")
252
- print("\n2. Verify write permissions in output directory")
253
- print("\n3. Check if certs/ and keys/ directories exist")
254
- return False
255
-
256
-
257
- def main() -> int:
258
- """Main function for command line execution."""
259
- parser = argparse.ArgumentParser(
260
- description="Setup test environment for MCP Proxy Adapter"
261
- )
262
- parser.add_argument(
263
- "--output-dir",
264
- "-o",
265
- type=str,
266
- default=".",
267
- help=(
268
- "Target directory to create the test environment "
269
- "(default: current directory)"
270
- ),
271
- )
272
- args = parser.parse_args()
273
- try:
274
- target_root = Path(args.output_dir)
275
- setup_test_environment(target_root)
276
- # Generate certificates if framework is available
277
- if SECURITY_FRAMEWORK_AVAILABLE:
278
- generate_certificates_with_framework(target_root)
279
- else:
280
- print(
281
- "⚠️ Skipping certificate generation (mcp_security_framework "
282
- "not available)"
283
- )
284
- except Exception as e:
285
- print(
286
- "❌ Error setting up test environment: {}".format(e),
287
- file=sys.stderr,
288
- )
289
- print("\n🔧 TROUBLESHOOTING:")
290
- print("1. Check if output directory is writable")
291
- print("2. Verify mcp_security_framework installation")
292
- print("3. Check available disk space")
293
- return 1
294
-
295
- print("\n" + "=" * 60)
296
- print("✅ TEST ENVIRONMENT SETUP COMPLETED SUCCESSFULLY")
297
- print("=" * 60)
298
- print("\n📋 NEXT STEPS:")
299
- print("1. Generate test configurations:")
300
- print(
301
- " python -m mcp_proxy_adapter.examples.generate_test_configs --output-dir configs"
302
- )
303
- print("\n2. Generate additional certificates (if needed):")
304
- print(" python -m mcp_proxy_adapter.examples.generate_certificates")
305
- print("\n3. Run security tests:")
306
- print(" python -m mcp_proxy_adapter.examples.run_security_tests")
307
- print("\n4. Start basic framework example:")
308
- print(
309
- " python -m mcp_proxy_adapter.examples.basic_framework.main --config configs/https_simple.json"
310
- )
311
- print("=" * 60)
312
- return 0
313
-
314
-
315
- if __name__ == "__main__":
316
- exit(main())