mcp-proxy-adapter 6.1.1__py3-none-any.whl → 6.2.0__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.
Files changed (145) hide show
  1. mcp_proxy_adapter/__main__.py +27 -7
  2. mcp_proxy_adapter/api/app.py +18 -7
  3. mcp_proxy_adapter/commands/ssl_setup_command.py +234 -351
  4. mcp_proxy_adapter/core/app_factory.py +87 -3
  5. mcp_proxy_adapter/core/app_runner.py +272 -0
  6. mcp_proxy_adapter/core/certificate_utils.py +291 -73
  7. mcp_proxy_adapter/core/client.py +574 -0
  8. mcp_proxy_adapter/core/client_manager.py +284 -0
  9. mcp_proxy_adapter/core/server_adapter.py +17 -80
  10. mcp_proxy_adapter/core/server_engine.py +5 -99
  11. mcp_proxy_adapter/core/ssl_utils.py +13 -12
  12. mcp_proxy_adapter/core/transport_manager.py +5 -5
  13. mcp_proxy_adapter/examples/__init__.py +16 -0
  14. mcp_proxy_adapter/examples/basic_framework/__init__.py +7 -0
  15. mcp_proxy_adapter/examples/basic_framework/commands/__init__.py +4 -0
  16. mcp_proxy_adapter/examples/basic_framework/hooks/__init__.py +4 -0
  17. mcp_proxy_adapter/examples/basic_framework/main.py +21 -40
  18. mcp_proxy_adapter/examples/commands/__init__.py +5 -1
  19. mcp_proxy_adapter/examples/create_certificates_simple.py +260 -75
  20. mcp_proxy_adapter/examples/debug_request_state.py +4 -36
  21. mcp_proxy_adapter/examples/debug_role_chain.py +2 -49
  22. mcp_proxy_adapter/examples/demo_client.py +0 -66
  23. mcp_proxy_adapter/examples/full_application/__init__.py +11 -0
  24. mcp_proxy_adapter/examples/full_application/commands/__init__.py +7 -0
  25. mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +0 -19
  26. mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +0 -16
  27. mcp_proxy_adapter/examples/full_application/hooks/__init__.py +7 -0
  28. mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +0 -22
  29. mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +0 -24
  30. mcp_proxy_adapter/examples/full_application/main.py +65 -44
  31. mcp_proxy_adapter/examples/full_application/proxy_endpoints.py +154 -0
  32. mcp_proxy_adapter/examples/generate_all_certificates.py +0 -67
  33. mcp_proxy_adapter/examples/generate_certificates.py +0 -15
  34. mcp_proxy_adapter/examples/generate_certificates_and_tokens.py +369 -0
  35. mcp_proxy_adapter/examples/generate_test_configs.py +204 -0
  36. mcp_proxy_adapter/examples/proxy_registration_example.py +3 -70
  37. mcp_proxy_adapter/examples/run_example.py +1 -23
  38. mcp_proxy_adapter/examples/run_security_tests.py +2 -60
  39. mcp_proxy_adapter/examples/run_security_tests_fixed.py +0 -53
  40. mcp_proxy_adapter/examples/security_test_client.py +18 -123
  41. mcp_proxy_adapter/examples/setup_test_environment.py +179 -0
  42. mcp_proxy_adapter/examples/test_config.py +148 -0
  43. mcp_proxy_adapter/examples/test_config_generator.py +1 -25
  44. mcp_proxy_adapter/examples/test_examples.py +4 -67
  45. mcp_proxy_adapter/examples/universal_client.py +154 -162
  46. mcp_proxy_adapter/main.py +51 -161
  47. mcp_proxy_adapter/version.py +1 -1
  48. mcp_proxy_adapter-6.2.0.dist-info/METADATA +687 -0
  49. mcp_proxy_adapter-6.2.0.dist-info/RECORD +122 -0
  50. mcp_proxy_adapter/docs/EN/TROUBLESHOOTING.md +0 -285
  51. mcp_proxy_adapter/docs/RU/TROUBLESHOOTING.md +0 -285
  52. mcp_proxy_adapter/examples/README.md +0 -257
  53. mcp_proxy_adapter/examples/README_EN.md +0 -258
  54. mcp_proxy_adapter/examples/SECURITY_TESTING.md +0 -455
  55. mcp_proxy_adapter/examples/basic_framework/configs/http_auth.json +0 -37
  56. mcp_proxy_adapter/examples/basic_framework/configs/http_simple.json +0 -23
  57. mcp_proxy_adapter/examples/basic_framework/configs/https_auth.json +0 -43
  58. mcp_proxy_adapter/examples/basic_framework/configs/https_no_protocol_middleware.json +0 -36
  59. mcp_proxy_adapter/examples/basic_framework/configs/https_simple.json +0 -29
  60. mcp_proxy_adapter/examples/basic_framework/configs/mtls_no_protocol_middleware.json +0 -34
  61. mcp_proxy_adapter/examples/basic_framework/configs/mtls_no_roles.json +0 -39
  62. mcp_proxy_adapter/examples/basic_framework/configs/mtls_simple.json +0 -35
  63. mcp_proxy_adapter/examples/basic_framework/configs/mtls_with_roles.json +0 -45
  64. mcp_proxy_adapter/examples/basic_framework/roles.json +0 -21
  65. mcp_proxy_adapter/examples/cert_config.json +0 -9
  66. mcp_proxy_adapter/examples/certs/admin.crt +0 -32
  67. mcp_proxy_adapter/examples/certs/admin.key +0 -52
  68. mcp_proxy_adapter/examples/certs/admin_cert.pem +0 -21
  69. mcp_proxy_adapter/examples/certs/admin_key.pem +0 -28
  70. mcp_proxy_adapter/examples/certs/ca_cert.pem +0 -23
  71. mcp_proxy_adapter/examples/certs/ca_cert.srl +0 -1
  72. mcp_proxy_adapter/examples/certs/ca_key.pem +0 -28
  73. mcp_proxy_adapter/examples/certs/cert_config.json +0 -9
  74. mcp_proxy_adapter/examples/certs/client.crt +0 -32
  75. mcp_proxy_adapter/examples/certs/client.key +0 -52
  76. mcp_proxy_adapter/examples/certs/client_admin.crt +0 -32
  77. mcp_proxy_adapter/examples/certs/client_admin.key +0 -52
  78. mcp_proxy_adapter/examples/certs/client_user.crt +0 -32
  79. mcp_proxy_adapter/examples/certs/client_user.key +0 -52
  80. mcp_proxy_adapter/examples/certs/guest_cert.pem +0 -21
  81. mcp_proxy_adapter/examples/certs/guest_key.pem +0 -28
  82. mcp_proxy_adapter/examples/certs/mcp_proxy_adapter_ca_ca.crt +0 -23
  83. mcp_proxy_adapter/examples/certs/proxy_cert.pem +0 -21
  84. mcp_proxy_adapter/examples/certs/proxy_key.pem +0 -28
  85. mcp_proxy_adapter/examples/certs/readonly.crt +0 -32
  86. mcp_proxy_adapter/examples/certs/readonly.key +0 -52
  87. mcp_proxy_adapter/examples/certs/readonly_cert.pem +0 -21
  88. mcp_proxy_adapter/examples/certs/readonly_key.pem +0 -28
  89. mcp_proxy_adapter/examples/certs/server.crt +0 -32
  90. mcp_proxy_adapter/examples/certs/server.key +0 -52
  91. mcp_proxy_adapter/examples/certs/server_cert.pem +0 -32
  92. mcp_proxy_adapter/examples/certs/server_key.pem +0 -52
  93. mcp_proxy_adapter/examples/certs/test_ca_ca.crt +0 -20
  94. mcp_proxy_adapter/examples/certs/user.crt +0 -32
  95. mcp_proxy_adapter/examples/certs/user.key +0 -52
  96. mcp_proxy_adapter/examples/certs/user_cert.pem +0 -21
  97. mcp_proxy_adapter/examples/certs/user_key.pem +0 -28
  98. mcp_proxy_adapter/examples/client_configs/api_key_client.json +0 -13
  99. mcp_proxy_adapter/examples/client_configs/basic_auth_client.json +0 -13
  100. mcp_proxy_adapter/examples/client_configs/certificate_client.json +0 -22
  101. mcp_proxy_adapter/examples/client_configs/jwt_client.json +0 -15
  102. mcp_proxy_adapter/examples/client_configs/no_auth_client.json +0 -9
  103. mcp_proxy_adapter/examples/full_application/configs/http_auth.json +0 -37
  104. mcp_proxy_adapter/examples/full_application/configs/http_simple.json +0 -23
  105. mcp_proxy_adapter/examples/full_application/configs/https_auth.json +0 -39
  106. mcp_proxy_adapter/examples/full_application/configs/https_simple.json +0 -25
  107. mcp_proxy_adapter/examples/full_application/configs/mtls_no_roles.json +0 -39
  108. mcp_proxy_adapter/examples/full_application/configs/mtls_with_roles.json +0 -45
  109. mcp_proxy_adapter/examples/full_application/roles.json +0 -21
  110. mcp_proxy_adapter/examples/keys/ca_key.pem +0 -28
  111. mcp_proxy_adapter/examples/keys/mcp_proxy_adapter_ca_ca.key +0 -28
  112. mcp_proxy_adapter/examples/keys/test_ca_ca.key +0 -28
  113. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log +0 -220
  114. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.1 +0 -1
  115. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.2 +0 -1
  116. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.3 +0 -1
  117. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.4 +0 -1
  118. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.5 +0 -1
  119. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log +0 -220
  120. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.1 +0 -1
  121. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.2 +0 -1
  122. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.3 +0 -1
  123. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.4 +0 -1
  124. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.5 +0 -1
  125. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log +0 -2
  126. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.1 +0 -1
  127. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.2 +0 -1
  128. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.3 +0 -1
  129. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.4 +0 -1
  130. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.5 +0 -1
  131. mcp_proxy_adapter/examples/roles.json +0 -38
  132. mcp_proxy_adapter/examples/server_configs/config_basic_http.json +0 -204
  133. mcp_proxy_adapter/examples/server_configs/config_http_token.json +0 -238
  134. mcp_proxy_adapter/examples/server_configs/config_https.json +0 -215
  135. mcp_proxy_adapter/examples/server_configs/config_https_token.json +0 -231
  136. mcp_proxy_adapter/examples/server_configs/config_mtls.json +0 -215
  137. mcp_proxy_adapter/examples/server_configs/config_proxy_registration.json +0 -250
  138. mcp_proxy_adapter/examples/server_configs/config_simple.json +0 -46
  139. mcp_proxy_adapter/examples/server_configs/roles.json +0 -38
  140. mcp_proxy_adapter-6.1.1.dist-info/METADATA +0 -205
  141. mcp_proxy_adapter-6.1.1.dist-info/RECORD +0 -197
  142. {mcp_proxy_adapter-6.1.1.dist-info → mcp_proxy_adapter-6.2.0.dist-info}/WHEEL +0 -0
  143. {mcp_proxy_adapter-6.1.1.dist-info → mcp_proxy_adapter-6.2.0.dist-info}/entry_points.txt +0 -0
  144. {mcp_proxy_adapter-6.1.1.dist-info → mcp_proxy_adapter-6.2.0.dist-info}/licenses/LICENSE +0 -0
  145. {mcp_proxy_adapter-6.1.1.dist-info → mcp_proxy_adapter-6.2.0.dist-info}/top_level.txt +0 -0
@@ -1,63 +1,44 @@
1
1
  #!/usr/bin/env python3
2
2
  """
3
- Basic Framework Example Application
4
-
5
- This is a simple application that demonstrates the basic usage of MCP Proxy Adapter framework.
6
-
3
+ Basic Framework Example
4
+ This example demonstrates the basic usage of the MCP Proxy Adapter framework
5
+ with minimal configuration and built-in commands.
7
6
  Author: Vasiliy Zdanovskiy
8
7
  email: vasilyvz@gmail.com
9
8
  """
10
-
11
9
  import sys
12
10
  import argparse
13
11
  from pathlib import Path
14
-
15
12
  # Add the framework to the path
16
13
  sys.path.insert(0, str(Path(__file__).parent.parent.parent))
17
-
18
- from mcp_proxy_adapter.api.app import create_app
19
- from mcp_proxy_adapter.config import Config
20
-
21
-
14
+ from mcp_proxy_adapter.core.app_factory import create_and_run_server
22
15
  def main():
23
16
  """Main entry point for the basic framework example."""
24
17
  parser = argparse.ArgumentParser(description="Basic Framework Example")
25
18
  parser.add_argument("--config", "-c", required=True, help="Path to configuration file")
26
- parser.add_argument("--host", default="0.0.0.0", help="Server host")
27
- parser.add_argument("--port", type=int, help="Server port (overrides config)")
19
+ parser.add_argument("--host", help="Server host")
20
+ parser.add_argument("--port", type=int, help="Server port")
28
21
  parser.add_argument("--debug", action="store_true", help="Enable debug mode")
29
-
30
22
  args = parser.parse_args()
31
-
32
- # Load configuration
33
- config = Config(args.config)
34
-
35
- # Override port if specified
23
+ # Override configuration if specified
24
+ config_overrides = {}
25
+ if args.host:
26
+ config_overrides["host"] = args.host
36
27
  if args.port:
37
- config.set("server.port", args.port)
38
-
39
- # Override debug if specified
28
+ config_overrides["port"] = args.port
40
29
  if args.debug:
41
- config.set("server.debug", True)
42
-
43
- # Create application
44
- app = create_app(app_config=config)
45
-
46
- # Get server configuration
47
- host = config.get("server.host", "0.0.0.0")
48
- port = config.get("server.port", 8000)
49
- debug = config.get("server.debug", False)
50
-
30
+ config_overrides["debug"] = True
51
31
  print(f"🚀 Starting Basic Framework Example")
52
32
  print(f"📋 Configuration: {args.config}")
53
- print(f"🌐 Server: {host}:{port}")
54
- print(f"🔧 Debug: {debug}")
55
33
  print("=" * 50)
56
-
57
- # Import uvicorn here to avoid dependency issues
58
- import uvicorn
59
- uvicorn.run(app, host=host, port=port, log_level="info")
60
-
61
-
34
+ # Use the factory method to create and run the server
35
+ create_and_run_server(
36
+ config_path=args.config,
37
+ title="Basic Framework Example",
38
+ description="Basic MCP Proxy Adapter with minimal configuration",
39
+ version="1.0.0",
40
+ host=config_overrides.get("host", "0.0.0.0"),
41
+ log_level="debug" if config_overrides.get("debug", False) else "info"
42
+ )
62
43
  if __name__ == "__main__":
63
44
  main()
@@ -1 +1,5 @@
1
- # Commands package
1
+ """Example Commands Package.
2
+
3
+ This package contains example command implementations demonstrating
4
+ various patterns for creating custom commands in MCP Proxy Adapter.
5
+ """
@@ -1,38 +1,50 @@
1
1
  #!/usr/bin/env python3
2
2
  """
3
3
  Simple Certificate Creation Script
4
-
5
- This script creates basic certificates for testing using OpenSSL directly.
6
-
4
+ This script creates basic certificates for testing using mcp_security_framework.
7
5
  Author: Vasiliy Zdanovskiy
8
6
  email: vasilyvz@gmail.com
9
7
  """
10
-
11
8
  import os
12
9
  import subprocess
13
10
  import sys
11
+ import argparse
14
12
  from pathlib import Path
15
-
16
-
13
+ # Import mcp_security_framework
14
+ try:
15
+ from mcp_security_framework.core.cert_manager import CertificateManager
16
+ from mcp_security_framework.schemas.config import CertificateConfig, CAConfig, ServerCertConfig, ClientCertConfig
17
+ from mcp_security_framework.schemas.models import CertificateType
18
+ SECURITY_FRAMEWORK_AVAILABLE = True
19
+ except ImportError:
20
+ SECURITY_FRAMEWORK_AVAILABLE = False
21
+ print("Warning: mcp_security_framework not available, falling back to OpenSSL")
17
22
  class SimpleCertificateCreator:
18
23
  """Create certificates using OpenSSL directly."""
19
-
20
- def __init__(self):
21
- self.project_root = Path(__file__).parent.parent.parent
22
- self.certs_dir = self.project_root / "mcp_proxy_adapter" / "examples" / "certs"
23
- self.keys_dir = self.project_root / "mcp_proxy_adapter" / "examples" / "keys"
24
-
24
+ def __init__(self, certs_dir: str = None, keys_dir: str = None):
25
+ if certs_dir:
26
+ self.certs_dir = Path(certs_dir).resolve()
27
+ else:
28
+ self.project_root = Path(__file__).parent.parent.parent
29
+ self.certs_dir = self.project_root / "mcp_proxy_adapter" / "examples" / "certs"
30
+ if keys_dir:
31
+ self.keys_dir = Path(keys_dir).resolve()
32
+ else:
33
+ if not certs_dir:
34
+ self.project_root = Path(__file__).parent.parent.parent
35
+ self.keys_dir = self.project_root / "mcp_proxy_adapter" / "examples" / "keys"
25
36
  # Create directories
26
37
  self.certs_dir.mkdir(parents=True, exist_ok=True)
27
38
  self.keys_dir.mkdir(parents=True, exist_ok=True)
28
-
39
+ print(f"🔧 Using certificates directory: {self.certs_dir}")
40
+ print(f"🔧 Using keys directory: {self.keys_dir}")
29
41
  def run_command(self, cmd: list, description: str) -> bool:
30
42
  """Run a command and handle errors."""
31
43
  try:
32
44
  print(f"🔧 {description}...")
45
+ # Use current working directory instead of project_root
33
46
  result = subprocess.run(
34
47
  cmd,
35
- cwd=self.project_root,
36
48
  capture_output=True,
37
49
  text=True,
38
50
  check=True
@@ -47,23 +59,73 @@ class SimpleCertificateCreator:
47
59
  except Exception as e:
48
60
  print(f"❌ {description} failed: {e}")
49
61
  return False
50
-
51
62
  def create_ca_certificate(self) -> bool:
52
- """Create CA certificate using OpenSSL."""
63
+ """Create CA certificate using mcp_security_framework or OpenSSL fallback."""
53
64
  ca_cert_path = self.certs_dir / "ca_cert.pem"
54
65
  ca_key_path = self.keys_dir / "ca_key.pem"
55
-
56
66
  if ca_cert_path.exists() and ca_key_path.exists():
57
67
  print(f"ℹ️ CA certificate already exists: {ca_cert_path}")
58
68
  return True
59
-
69
+ if SECURITY_FRAMEWORK_AVAILABLE:
70
+ return self._create_ca_certificate_with_framework()
71
+ else:
72
+ return self._create_ca_certificate_with_openssl()
73
+ def _create_ca_certificate_with_framework(self) -> bool:
74
+ """Create CA certificate using mcp_security_framework."""
75
+ try:
76
+ print("🔧 Creating CA certificate using mcp_security_framework...")
77
+ # Create CA certificate configuration
78
+ ca_config = CAConfig(
79
+ common_name="mcp_proxy_adapter_test_ca",
80
+ organization="Test Organization",
81
+ organizational_unit="Test Unit",
82
+ country="US",
83
+ state="Test State",
84
+ locality="Test City",
85
+ validity_years=10
86
+ )
87
+ # Create certificate manager
88
+ cert_config = CertificateConfig(
89
+ cert_storage_path=str(self.certs_dir),
90
+ key_storage_path=str(self.keys_dir),
91
+ default_validity_days=365,
92
+ key_size=2048,
93
+ hash_algorithm="sha256"
94
+ )
95
+ cert_manager = CertificateManager(cert_config)
96
+ # Create CA certificate
97
+ cert_pair = cert_manager.create_root_ca(ca_config)
98
+ if cert_pair and cert_pair.certificate_path and cert_pair.private_key_path:
99
+ # Rename the generated files to the expected names
100
+ generated_cert = Path(cert_pair.certificate_path)
101
+ generated_key = Path(cert_pair.private_key_path)
102
+ if generated_cert.exists() and generated_key.exists():
103
+ # Move to expected names
104
+ expected_cert = self.certs_dir / "ca_cert.pem"
105
+ expected_key = self.keys_dir / "ca_key.pem"
106
+ generated_cert.rename(expected_cert)
107
+ generated_key.rename(expected_key)
108
+ print("✅ CA certificate created successfully using mcp_security_framework")
109
+ return True
110
+ else:
111
+ print("❌ Generated CA certificate files not found")
112
+ return False
113
+ else:
114
+ print("❌ Failed to create CA certificate: Invalid certificate pair")
115
+ return False
116
+ except Exception as e:
117
+ print(f"❌ Error creating CA certificate with framework: {e}")
118
+ return False
119
+ def _create_ca_certificate_with_openssl(self) -> bool:
120
+ """Create CA certificate using OpenSSL fallback."""
121
+ ca_cert_path = self.certs_dir / "ca_cert.pem"
122
+ ca_key_path = self.keys_dir / "ca_key.pem"
60
123
  # Create CA private key
61
124
  key_cmd = [
62
125
  "openssl", "genrsa", "-out", str(ca_key_path), "2048"
63
126
  ]
64
127
  if not self.run_command(key_cmd, "Creating CA private key"):
65
128
  return False
66
-
67
129
  # Create CA certificate
68
130
  cert_cmd = [
69
131
  "openssl", "req", "-new", "-x509", "-days", "3650",
@@ -72,23 +134,97 @@ class SimpleCertificateCreator:
72
134
  "-subj", "/C=US/ST=Test State/L=Test City/O=Test Organization/CN=MCP Proxy Adapter Test CA"
73
135
  ]
74
136
  return self.run_command(cert_cmd, "Creating CA certificate")
75
-
76
137
  def create_server_certificate(self) -> bool:
77
- """Create server certificate using OpenSSL."""
138
+ """Create server certificate using mcp_security_framework or OpenSSL fallback."""
78
139
  server_cert_path = self.certs_dir / "server_cert.pem"
79
140
  server_key_path = self.certs_dir / "server_key.pem"
80
-
81
141
  if server_cert_path.exists() and server_key_path.exists():
82
- print(f"ℹ️ Server certificate already exists: {server_cert_path}")
142
+ print("ℹ️ Server certificate already exists")
83
143
  return True
84
-
144
+ if SECURITY_FRAMEWORK_AVAILABLE:
145
+ return self._create_server_certificate_with_framework()
146
+ else:
147
+ return self._create_server_certificate_with_openssl()
148
+ def _create_server_certificate_with_framework(self) -> bool:
149
+ """Create server certificate using mcp_security_framework."""
150
+ try:
151
+ print("🔧 Creating server certificate using mcp_security_framework...")
152
+ # Find CA certificate and key files
153
+ ca_cert_path = None
154
+ ca_key_path = None
155
+ # Look for CA certificate files with expected names
156
+ expected_ca_cert = self.certs_dir / "ca_cert.pem"
157
+ expected_ca_key = self.keys_dir / "ca_key.pem"
158
+ if expected_ca_cert.exists():
159
+ ca_cert_path = str(expected_ca_cert)
160
+ else:
161
+ # Fallback: look for CA certificate files with pattern
162
+ for cert_file in self.certs_dir.glob("*_ca.crt"):
163
+ ca_cert_path = str(cert_file)
164
+ break
165
+ if expected_ca_key.exists():
166
+ ca_key_path = str(expected_ca_key)
167
+ else:
168
+ # Fallback: look for CA key files with pattern
169
+ for key_file in self.keys_dir.glob("*_ca.key"):
170
+ ca_key_path = str(key_file)
171
+ break
172
+ if not ca_cert_path or not ca_key_path:
173
+ print("❌ CA certificate or key not found")
174
+ return False
175
+ # Create server certificate configuration
176
+ server_config = ServerCertConfig(
177
+ common_name="localhost",
178
+ organization="Test Organization",
179
+ organizational_unit="Test Unit",
180
+ country="US",
181
+ state="Test State",
182
+ locality="Test City",
183
+ subject_alt_names=["localhost", "127.0.0.1"],
184
+ validity_years=1,
185
+ ca_cert_path=ca_cert_path,
186
+ ca_key_path=ca_key_path
187
+ )
188
+ # Create certificate manager
189
+ cert_config = CertificateConfig(
190
+ cert_storage_path=str(self.certs_dir),
191
+ key_storage_path=str(self.certs_dir), # Server keys in certs dir
192
+ default_validity_days=365,
193
+ key_size=2048,
194
+ hash_algorithm="sha256"
195
+ )
196
+ cert_manager = CertificateManager(cert_config)
197
+ # Create server certificate
198
+ cert_pair = cert_manager.create_server_certificate(server_config)
199
+ if cert_pair and cert_pair.certificate_path and cert_pair.private_key_path:
200
+ # Rename the generated files to the expected names
201
+ generated_cert = Path(cert_pair.certificate_path)
202
+ generated_key = Path(cert_pair.private_key_path)
203
+ if generated_cert.exists() and generated_key.exists():
204
+ # Move to expected names
205
+ generated_cert.rename(self.certs_dir / "server_cert.pem")
206
+ generated_key.rename(self.certs_dir / "server_key.pem")
207
+ print("✅ Server certificate created successfully using mcp_security_framework")
208
+ return True
209
+ else:
210
+ print("❌ Generated certificate files not found")
211
+ return False
212
+ else:
213
+ print("❌ Failed to create server certificate: Invalid certificate pair")
214
+ return False
215
+ except Exception as e:
216
+ print(f"❌ Error creating server certificate with framework: {e}")
217
+ return False
218
+ def _create_server_certificate_with_openssl(self) -> bool:
219
+ """Create server certificate using OpenSSL fallback."""
220
+ server_cert_path = self.certs_dir / "server_cert.pem"
221
+ server_key_path = self.certs_dir / "server_key.pem"
85
222
  # Create server private key
86
223
  key_cmd = [
87
224
  "openssl", "genrsa", "-out", str(server_key_path), "2048"
88
225
  ]
89
226
  if not self.run_command(key_cmd, "Creating server private key"):
90
227
  return False
91
-
92
228
  # Create server certificate signing request
93
229
  csr_path = self.certs_dir / "server.csr"
94
230
  csr_cmd = [
@@ -99,7 +235,6 @@ class SimpleCertificateCreator:
99
235
  ]
100
236
  if not self.run_command(csr_cmd, "Creating server CSR"):
101
237
  return False
102
-
103
238
  # Create server certificate
104
239
  cert_cmd = [
105
240
  "openssl", "x509", "-req", "-days", "730",
@@ -110,29 +245,102 @@ class SimpleCertificateCreator:
110
245
  "-out", str(server_cert_path)
111
246
  ]
112
247
  success = self.run_command(cert_cmd, "Creating server certificate")
113
-
114
248
  # Clean up CSR
115
249
  if csr_path.exists():
116
250
  csr_path.unlink()
117
-
118
251
  return success
119
-
120
- def create_client_certificate(self, name: str, common_name: str) -> bool:
121
- """Create client certificate using OpenSSL."""
252
+ def create_client_certificate(self, name: str, common_name: str, roles: list = None, permissions: list = None) -> bool:
253
+ """Create client certificate using mcp_security_framework or OpenSSL fallback."""
122
254
  cert_path = self.certs_dir / f"{name}_cert.pem"
123
255
  key_path = self.certs_dir / f"{name}_key.pem"
124
-
125
256
  if cert_path.exists() and key_path.exists():
126
257
  print(f"ℹ️ Client certificate {name} already exists: {cert_path}")
127
258
  return True
128
-
259
+ if SECURITY_FRAMEWORK_AVAILABLE:
260
+ return self._create_client_certificate_with_framework(name, common_name, roles, permissions)
261
+ else:
262
+ return self._create_client_certificate_with_openssl(name, common_name)
263
+ def _create_client_certificate_with_framework(self, name: str, common_name: str, roles: list = None, permissions: list = None) -> bool:
264
+ """Create client certificate using mcp_security_framework."""
265
+ try:
266
+ print(f"🔧 Creating client certificate {name} using mcp_security_framework...")
267
+ # Find CA certificate and key files
268
+ ca_cert_path = None
269
+ ca_key_path = None
270
+ # Look for CA certificate files with expected names
271
+ expected_ca_cert = self.certs_dir / "ca_cert.pem"
272
+ expected_ca_key = self.keys_dir / "ca_key.pem"
273
+ if expected_ca_cert.exists():
274
+ ca_cert_path = str(expected_ca_cert)
275
+ else:
276
+ # Fallback: look for CA certificate files with pattern
277
+ for cert_file in self.certs_dir.glob("*_ca.crt"):
278
+ ca_cert_path = str(cert_file)
279
+ break
280
+ if expected_ca_key.exists():
281
+ ca_key_path = str(expected_ca_key)
282
+ else:
283
+ # Fallback: look for CA key files with pattern
284
+ for key_file in self.keys_dir.glob("*_ca.key"):
285
+ ca_key_path = str(key_file)
286
+ break
287
+ if not ca_cert_path or not ca_key_path:
288
+ print("❌ CA certificate or key not found")
289
+ return False
290
+ # Create client certificate configuration
291
+ client_config = ClientCertConfig(
292
+ common_name=common_name,
293
+ organization="Test Organization",
294
+ organizational_unit="Test Unit",
295
+ country="US",
296
+ state="Test State",
297
+ locality="Test City",
298
+ validity_years=1,
299
+ ca_cert_path=ca_cert_path,
300
+ ca_key_path=ca_key_path
301
+ )
302
+ # Create certificate manager
303
+ cert_config = CertificateConfig(
304
+ cert_storage_path=str(self.certs_dir),
305
+ key_storage_path=str(self.certs_dir), # Client keys in certs dir
306
+ default_validity_days=365,
307
+ key_size=2048,
308
+ hash_algorithm="sha256"
309
+ )
310
+ cert_manager = CertificateManager(cert_config)
311
+ # Create client certificate
312
+ cert_pair = cert_manager.create_client_certificate(client_config)
313
+ if cert_pair and cert_pair.certificate_path and cert_pair.private_key_path:
314
+ # Rename the generated files to the expected names
315
+ generated_cert = Path(cert_pair.certificate_path)
316
+ generated_key = Path(cert_pair.private_key_path)
317
+ if generated_cert.exists() and generated_key.exists():
318
+ # Move to expected names
319
+ expected_cert = self.certs_dir / f"{name}_cert.pem"
320
+ expected_key = self.certs_dir / f"{name}_key.pem"
321
+ generated_cert.rename(expected_cert)
322
+ generated_key.rename(expected_key)
323
+ print(f"✅ Client certificate {name} created successfully using mcp_security_framework")
324
+ return True
325
+ else:
326
+ print(f"❌ Generated certificate files not found for {name}")
327
+ return False
328
+ else:
329
+ print(f"❌ Failed to create client certificate {name}: Invalid certificate pair")
330
+ return False
331
+ except Exception as e:
332
+ print(f"❌ Error creating client certificate {name} with framework: {e}")
333
+ return False
334
+ def _create_client_certificate_with_openssl(self, name: str, common_name: str) -> bool:
335
+ """Create client certificate using OpenSSL fallback."""
336
+ cert_path = self.certs_dir / f"{name}_cert.pem"
337
+ key_path = self.certs_dir / f"{name}_key.pem"
129
338
  # Create client private key
130
339
  key_cmd = [
131
340
  "openssl", "genrsa", "-out", str(key_path), "2048"
132
341
  ]
133
342
  if not self.run_command(key_cmd, f"Creating {name} private key"):
134
343
  return False
135
-
136
344
  # Create client certificate signing request
137
345
  csr_path = self.certs_dir / f"{name}.csr"
138
346
  csr_cmd = [
@@ -143,7 +351,6 @@ class SimpleCertificateCreator:
143
351
  ]
144
352
  if not self.run_command(csr_cmd, f"Creating {name} CSR"):
145
353
  return False
146
-
147
354
  # Create client certificate
148
355
  cert_cmd = [
149
356
  "openssl", "x509", "-req", "-days", "730",
@@ -154,45 +361,36 @@ class SimpleCertificateCreator:
154
361
  "-out", str(cert_path)
155
362
  ]
156
363
  success = self.run_command(cert_cmd, f"Creating {name} certificate")
157
-
158
364
  # Clean up CSR
159
365
  if csr_path.exists():
160
366
  csr_path.unlink()
161
-
162
367
  return success
163
-
164
368
  def create_legacy_certificates(self) -> bool:
165
369
  """Create legacy certificate files for compatibility."""
166
370
  legacy_files = [
167
- ("client.crt", "client.key", "client"),
168
371
  ("client_admin.crt", "client_admin.key", "admin"),
169
372
  ("admin.crt", "admin.key", "admin"),
170
373
  ("user.crt", "user.key", "user"),
171
374
  ("readonly.crt", "readonly.key", "readonly")
172
375
  ]
173
-
174
376
  success = True
175
377
  for cert_file, key_file, source_name in legacy_files:
176
378
  cert_path = self.certs_dir / cert_file
177
379
  key_path = self.certs_dir / key_file
178
-
179
380
  if not cert_path.exists() or not key_path.exists():
180
381
  source_cert = self.certs_dir / f"{source_name}_cert.pem"
181
382
  source_key = self.certs_dir / f"{source_name}_key.pem"
182
-
183
383
  if source_cert.exists() and source_key.exists():
184
384
  self.run_command(["cp", str(source_cert), str(cert_path)], f"Creating {cert_file}")
185
385
  self.run_command(["cp", str(source_key), str(key_path)], f"Creating {key_file}")
186
386
  else:
187
387
  print(f"⚠️ Source certificate {source_name} not found for {cert_file}")
188
- success = False
189
-
190
- return success
191
-
388
+ # Don't fail the entire process for missing legacy certificates
389
+ continue
390
+ return True # Always return True for legacy certificates
192
391
  def validate_certificates(self) -> bool:
193
392
  """Validate all created certificates."""
194
393
  print("\n🔍 Validating certificates...")
195
-
196
394
  cert_files = [
197
395
  "ca_cert.pem",
198
396
  "server_cert.pem",
@@ -202,7 +400,6 @@ class SimpleCertificateCreator:
202
400
  "guest_cert.pem",
203
401
  "proxy_cert.pem"
204
402
  ]
205
-
206
403
  success = True
207
404
  for cert_file in cert_files:
208
405
  cert_path = self.certs_dir / cert_file
@@ -220,78 +417,68 @@ class SimpleCertificateCreator:
220
417
  success = False
221
418
  else:
222
419
  print(f"⚠️ {cert_file}: Not found")
223
-
224
420
  return success
225
-
226
421
  def create_all(self) -> bool:
227
422
  """Create all certificates."""
228
423
  print("🔐 Creating All Certificates for Security Testing")
229
424
  print("=" * 60)
230
-
231
425
  success = True
232
-
233
426
  # 1. Create CA certificate
234
427
  if not self.create_ca_certificate():
235
428
  success = False
236
429
  print("❌ Cannot continue without CA certificate")
237
430
  return False
238
-
239
431
  # 2. Create server certificate
240
432
  if not self.create_server_certificate():
241
433
  success = False
242
-
243
434
  # 3. Create client certificates
244
435
  print("\n👥 Creating client certificates...")
245
436
  client_certs = [
246
- ("admin", "admin-client"),
247
- ("user", "user-client"),
248
- ("readonly", "readonly-client"),
249
- ("guest", "guest-client"),
250
- ("proxy", "proxy-client")
437
+ ("admin", "admin-client", ["admin"], ["read", "write", "execute", "delete", "admin", "register", "unregister", "heartbeat", "discover"]),
438
+ ("user", "user-client", ["user"], ["read", "execute", "register", "unregister", "heartbeat", "discover"]),
439
+ ("readonly", "readonly-client", ["readonly"], ["read", "discover"]),
440
+ ("guest", "guest-client", ["guest"], ["read", "discover"]),
441
+ ("proxy", "proxy-client", ["proxy"], ["register", "unregister", "heartbeat", "discover"])
251
442
  ]
252
-
253
- for name, common_name in client_certs:
254
- if not self.create_client_certificate(name, common_name):
443
+ for name, common_name, roles, permissions in client_certs:
444
+ if not self.create_client_certificate(name, common_name, roles, permissions):
255
445
  success = False
256
-
257
446
  # 4. Create legacy certificates
258
447
  print("\n🔄 Creating legacy certificates...")
259
448
  if not self.create_legacy_certificates():
260
449
  success = False
261
-
262
450
  # 5. Validate certificates
263
451
  if not self.validate_certificates():
264
452
  success = False
265
-
266
453
  # Print summary
267
454
  print("\n" + "=" * 60)
268
455
  print("📊 CERTIFICATE CREATION SUMMARY")
269
456
  print("=" * 60)
270
-
271
457
  if success:
272
458
  print("✅ All certificates created successfully!")
273
459
  print(f"📁 Certificates directory: {self.certs_dir}")
274
460
  print(f"🔑 Keys directory: {self.keys_dir}")
275
461
  print("\n📋 Created certificates:")
276
-
277
462
  cert_files = list(self.certs_dir.glob("*.pem")) + list(self.certs_dir.glob("*.crt"))
278
463
  for cert_file in sorted(cert_files):
279
464
  print(f" - {cert_file.name}")
280
-
281
465
  key_files = list(self.keys_dir.glob("*.pem")) + list(self.keys_dir.glob("*.key"))
282
466
  for key_file in sorted(key_files):
283
467
  print(f" - {key_file.name}")
284
468
  else:
285
469
  print("❌ Some certificates failed to create")
286
470
  print("Check the error messages above")
287
-
288
471
  return success
289
-
290
-
291
472
  def main():
292
473
  """Main function."""
293
- creator = SimpleCertificateCreator()
294
-
474
+ parser = argparse.ArgumentParser(description="Create certificates for testing")
475
+ parser.add_argument("--certs-dir", help="Directory for certificates")
476
+ parser.add_argument("--keys-dir", help="Directory for keys")
477
+ args = parser.parse_args()
478
+ creator = SimpleCertificateCreator(
479
+ certs_dir=args.certs_dir,
480
+ keys_dir=args.keys_dir
481
+ )
295
482
  try:
296
483
  success = creator.create_all()
297
484
  sys.exit(0 if success else 1)
@@ -301,7 +488,5 @@ def main():
301
488
  except Exception as e:
302
489
  print(f"\n❌ Certificate creation failed: {e}")
303
490
  sys.exit(1)
304
-
305
-
306
491
  if __name__ == "__main__":
307
492
  main()