mcp-proxy-adapter 4.1.1__py3-none-any.whl → 6.0.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.
Files changed (200) hide show
  1. mcp_proxy_adapter/__main__.py +32 -0
  2. mcp_proxy_adapter/api/app.py +290 -33
  3. mcp_proxy_adapter/api/handlers.py +32 -6
  4. mcp_proxy_adapter/api/middleware/__init__.py +38 -32
  5. mcp_proxy_adapter/api/middleware/command_permission_middleware.py +148 -0
  6. mcp_proxy_adapter/api/middleware/error_handling.py +9 -0
  7. mcp_proxy_adapter/api/middleware/factory.py +243 -0
  8. mcp_proxy_adapter/api/middleware/logging.py +32 -6
  9. mcp_proxy_adapter/api/middleware/protocol_middleware.py +201 -0
  10. mcp_proxy_adapter/api/middleware/transport_middleware.py +122 -0
  11. mcp_proxy_adapter/api/middleware/unified_security.py +197 -0
  12. mcp_proxy_adapter/api/middleware/user_info_middleware.py +158 -0
  13. mcp_proxy_adapter/commands/__init__.py +19 -4
  14. mcp_proxy_adapter/commands/auth_validation_command.py +408 -0
  15. mcp_proxy_adapter/commands/base.py +66 -32
  16. mcp_proxy_adapter/commands/builtin_commands.py +95 -0
  17. mcp_proxy_adapter/commands/catalog_manager.py +838 -0
  18. mcp_proxy_adapter/commands/cert_monitor_command.py +620 -0
  19. mcp_proxy_adapter/commands/certificate_management_command.py +608 -0
  20. mcp_proxy_adapter/commands/command_registry.py +711 -354
  21. mcp_proxy_adapter/commands/dependency_manager.py +245 -0
  22. mcp_proxy_adapter/commands/echo_command.py +81 -0
  23. mcp_proxy_adapter/commands/health_command.py +8 -1
  24. mcp_proxy_adapter/commands/help_command.py +21 -14
  25. mcp_proxy_adapter/commands/hooks.py +200 -167
  26. mcp_proxy_adapter/commands/key_management_command.py +506 -0
  27. mcp_proxy_adapter/commands/load_command.py +176 -0
  28. mcp_proxy_adapter/commands/plugins_command.py +235 -0
  29. mcp_proxy_adapter/commands/protocol_management_command.py +232 -0
  30. mcp_proxy_adapter/commands/proxy_registration_command.py +409 -0
  31. mcp_proxy_adapter/commands/reload_command.py +48 -50
  32. mcp_proxy_adapter/commands/result.py +1 -0
  33. mcp_proxy_adapter/commands/role_test_command.py +141 -0
  34. mcp_proxy_adapter/commands/roles_management_command.py +697 -0
  35. mcp_proxy_adapter/commands/security_command.py +488 -0
  36. mcp_proxy_adapter/commands/ssl_setup_command.py +366 -0
  37. mcp_proxy_adapter/commands/token_management_command.py +529 -0
  38. mcp_proxy_adapter/commands/transport_management_command.py +144 -0
  39. mcp_proxy_adapter/commands/unload_command.py +158 -0
  40. mcp_proxy_adapter/config.py +394 -14
  41. mcp_proxy_adapter/core/app_factory.py +410 -0
  42. mcp_proxy_adapter/core/app_runner.py +272 -0
  43. mcp_proxy_adapter/core/auth_validator.py +606 -0
  44. mcp_proxy_adapter/core/certificate_utils.py +1045 -0
  45. mcp_proxy_adapter/core/client.py +574 -0
  46. mcp_proxy_adapter/core/client_manager.py +284 -0
  47. mcp_proxy_adapter/core/client_security.py +384 -0
  48. mcp_proxy_adapter/core/config_converter.py +405 -0
  49. mcp_proxy_adapter/core/config_validator.py +218 -0
  50. mcp_proxy_adapter/core/logging.py +19 -3
  51. mcp_proxy_adapter/core/mtls_asgi.py +156 -0
  52. mcp_proxy_adapter/core/mtls_asgi_app.py +187 -0
  53. mcp_proxy_adapter/core/protocol_manager.py +385 -0
  54. mcp_proxy_adapter/core/proxy_client.py +602 -0
  55. mcp_proxy_adapter/core/proxy_registration.py +522 -0
  56. mcp_proxy_adapter/core/role_utils.py +426 -0
  57. mcp_proxy_adapter/core/security_adapter.py +370 -0
  58. mcp_proxy_adapter/core/security_factory.py +239 -0
  59. mcp_proxy_adapter/core/security_integration.py +286 -0
  60. mcp_proxy_adapter/core/server_adapter.py +282 -0
  61. mcp_proxy_adapter/core/server_engine.py +270 -0
  62. mcp_proxy_adapter/core/settings.py +1 -0
  63. mcp_proxy_adapter/core/ssl_utils.py +234 -0
  64. mcp_proxy_adapter/core/transport_manager.py +292 -0
  65. mcp_proxy_adapter/core/unified_config_adapter.py +579 -0
  66. mcp_proxy_adapter/custom_openapi.py +22 -11
  67. mcp_proxy_adapter/examples/__init__.py +13 -4
  68. mcp_proxy_adapter/examples/basic_framework/__init__.py +9 -0
  69. mcp_proxy_adapter/examples/basic_framework/commands/__init__.py +4 -0
  70. mcp_proxy_adapter/examples/basic_framework/hooks/__init__.py +4 -0
  71. mcp_proxy_adapter/examples/basic_framework/main.py +44 -0
  72. mcp_proxy_adapter/examples/commands/__init__.py +5 -0
  73. mcp_proxy_adapter/examples/create_certificates_simple.py +550 -0
  74. mcp_proxy_adapter/examples/debug_request_state.py +112 -0
  75. mcp_proxy_adapter/examples/debug_role_chain.py +158 -0
  76. mcp_proxy_adapter/examples/demo_client.py +275 -0
  77. mcp_proxy_adapter/examples/examples/basic_framework/__init__.py +9 -0
  78. mcp_proxy_adapter/examples/examples/basic_framework/commands/__init__.py +4 -0
  79. mcp_proxy_adapter/examples/examples/basic_framework/hooks/__init__.py +4 -0
  80. mcp_proxy_adapter/examples/examples/basic_framework/main.py +44 -0
  81. mcp_proxy_adapter/examples/examples/full_application/__init__.py +12 -0
  82. mcp_proxy_adapter/examples/examples/full_application/commands/__init__.py +7 -0
  83. mcp_proxy_adapter/examples/examples/full_application/commands/custom_echo_command.py +80 -0
  84. mcp_proxy_adapter/examples/examples/full_application/commands/dynamic_calculator_command.py +90 -0
  85. mcp_proxy_adapter/examples/examples/full_application/hooks/__init__.py +7 -0
  86. mcp_proxy_adapter/examples/examples/full_application/hooks/application_hooks.py +75 -0
  87. mcp_proxy_adapter/examples/examples/full_application/hooks/builtin_command_hooks.py +71 -0
  88. mcp_proxy_adapter/examples/examples/full_application/main.py +173 -0
  89. mcp_proxy_adapter/examples/examples/full_application/proxy_endpoints.py +154 -0
  90. mcp_proxy_adapter/examples/full_application/__init__.py +12 -0
  91. mcp_proxy_adapter/examples/full_application/commands/__init__.py +7 -0
  92. mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +80 -0
  93. mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +90 -0
  94. mcp_proxy_adapter/examples/full_application/hooks/__init__.py +7 -0
  95. mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +75 -0
  96. mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +71 -0
  97. mcp_proxy_adapter/examples/full_application/main.py +173 -0
  98. mcp_proxy_adapter/examples/full_application/proxy_endpoints.py +154 -0
  99. mcp_proxy_adapter/examples/generate_all_certificates.py +362 -0
  100. mcp_proxy_adapter/examples/generate_certificates.py +177 -0
  101. mcp_proxy_adapter/examples/generate_certificates_and_tokens.py +369 -0
  102. mcp_proxy_adapter/examples/generate_test_configs.py +331 -0
  103. mcp_proxy_adapter/examples/proxy_registration_example.py +334 -0
  104. mcp_proxy_adapter/examples/run_example.py +59 -0
  105. mcp_proxy_adapter/examples/run_full_test_suite.py +318 -0
  106. mcp_proxy_adapter/examples/run_proxy_server.py +146 -0
  107. mcp_proxy_adapter/examples/run_security_tests.py +544 -0
  108. mcp_proxy_adapter/examples/run_security_tests_fixed.py +247 -0
  109. mcp_proxy_adapter/examples/scripts/config_generator.py +740 -0
  110. mcp_proxy_adapter/examples/scripts/create_certificates_simple.py +560 -0
  111. mcp_proxy_adapter/examples/scripts/generate_certificates_and_tokens.py +369 -0
  112. mcp_proxy_adapter/examples/security_test_client.py +782 -0
  113. mcp_proxy_adapter/examples/setup_test_environment.py +328 -0
  114. mcp_proxy_adapter/examples/test_config.py +148 -0
  115. mcp_proxy_adapter/examples/test_config_generator.py +86 -0
  116. mcp_proxy_adapter/examples/test_examples.py +281 -0
  117. mcp_proxy_adapter/examples/universal_client.py +620 -0
  118. mcp_proxy_adapter/main.py +93 -0
  119. mcp_proxy_adapter/utils/config_generator.py +1008 -0
  120. mcp_proxy_adapter/version.py +5 -2
  121. mcp_proxy_adapter-6.0.1.dist-info/METADATA +679 -0
  122. mcp_proxy_adapter-6.0.1.dist-info/RECORD +140 -0
  123. mcp_proxy_adapter-6.0.1.dist-info/entry_points.txt +2 -0
  124. {mcp_proxy_adapter-4.1.1.dist-info → mcp_proxy_adapter-6.0.1.dist-info}/licenses/LICENSE +2 -2
  125. mcp_proxy_adapter/api/middleware/auth.py +0 -146
  126. mcp_proxy_adapter/api/middleware/rate_limit.py +0 -152
  127. mcp_proxy_adapter/commands/reload_settings_command.py +0 -125
  128. mcp_proxy_adapter/examples/README.md +0 -124
  129. mcp_proxy_adapter/examples/basic_server/README.md +0 -60
  130. mcp_proxy_adapter/examples/basic_server/__init__.py +0 -7
  131. mcp_proxy_adapter/examples/basic_server/basic_custom_settings.json +0 -39
  132. mcp_proxy_adapter/examples/basic_server/config.json +0 -35
  133. mcp_proxy_adapter/examples/basic_server/custom_settings_example.py +0 -238
  134. mcp_proxy_adapter/examples/basic_server/server.py +0 -103
  135. mcp_proxy_adapter/examples/custom_commands/README.md +0 -127
  136. mcp_proxy_adapter/examples/custom_commands/__init__.py +0 -27
  137. mcp_proxy_adapter/examples/custom_commands/advanced_hooks.py +0 -250
  138. mcp_proxy_adapter/examples/custom_commands/auto_commands/__init__.py +0 -6
  139. mcp_proxy_adapter/examples/custom_commands/auto_commands/auto_echo_command.py +0 -103
  140. mcp_proxy_adapter/examples/custom_commands/auto_commands/auto_info_command.py +0 -111
  141. mcp_proxy_adapter/examples/custom_commands/config.json +0 -35
  142. mcp_proxy_adapter/examples/custom_commands/custom_health_command.py +0 -169
  143. mcp_proxy_adapter/examples/custom_commands/custom_help_command.py +0 -215
  144. mcp_proxy_adapter/examples/custom_commands/custom_openapi_generator.py +0 -76
  145. mcp_proxy_adapter/examples/custom_commands/custom_settings.json +0 -96
  146. mcp_proxy_adapter/examples/custom_commands/custom_settings_manager.py +0 -241
  147. mcp_proxy_adapter/examples/custom_commands/data_transform_command.py +0 -135
  148. mcp_proxy_adapter/examples/custom_commands/echo_command.py +0 -122
  149. mcp_proxy_adapter/examples/custom_commands/hooks.py +0 -230
  150. mcp_proxy_adapter/examples/custom_commands/intercept_command.py +0 -123
  151. mcp_proxy_adapter/examples/custom_commands/manual_echo_command.py +0 -103
  152. mcp_proxy_adapter/examples/custom_commands/server.py +0 -228
  153. mcp_proxy_adapter/examples/custom_commands/test_hooks.py +0 -176
  154. mcp_proxy_adapter/examples/deployment/README.md +0 -49
  155. mcp_proxy_adapter/examples/deployment/__init__.py +0 -7
  156. mcp_proxy_adapter/examples/deployment/config.development.json +0 -8
  157. mcp_proxy_adapter/examples/deployment/config.json +0 -29
  158. mcp_proxy_adapter/examples/deployment/config.production.json +0 -12
  159. mcp_proxy_adapter/examples/deployment/config.staging.json +0 -11
  160. mcp_proxy_adapter/examples/deployment/docker-compose.yml +0 -31
  161. mcp_proxy_adapter/examples/deployment/run.sh +0 -43
  162. mcp_proxy_adapter/examples/deployment/run_docker.sh +0 -84
  163. mcp_proxy_adapter/schemas/base_schema.json +0 -114
  164. mcp_proxy_adapter/schemas/openapi_schema.json +0 -314
  165. mcp_proxy_adapter/tests/__init__.py +0 -0
  166. mcp_proxy_adapter/tests/api/__init__.py +0 -3
  167. mcp_proxy_adapter/tests/api/test_cmd_endpoint.py +0 -115
  168. mcp_proxy_adapter/tests/api/test_custom_openapi.py +0 -617
  169. mcp_proxy_adapter/tests/api/test_handlers.py +0 -522
  170. mcp_proxy_adapter/tests/api/test_middleware.py +0 -340
  171. mcp_proxy_adapter/tests/api/test_schemas.py +0 -546
  172. mcp_proxy_adapter/tests/api/test_tool_integration.py +0 -531
  173. mcp_proxy_adapter/tests/commands/__init__.py +0 -3
  174. mcp_proxy_adapter/tests/commands/test_config_command.py +0 -211
  175. mcp_proxy_adapter/tests/commands/test_echo_command.py +0 -127
  176. mcp_proxy_adapter/tests/commands/test_help_command.py +0 -136
  177. mcp_proxy_adapter/tests/conftest.py +0 -131
  178. mcp_proxy_adapter/tests/functional/__init__.py +0 -3
  179. mcp_proxy_adapter/tests/functional/test_api.py +0 -253
  180. mcp_proxy_adapter/tests/integration/__init__.py +0 -3
  181. mcp_proxy_adapter/tests/integration/test_cmd_integration.py +0 -129
  182. mcp_proxy_adapter/tests/integration/test_integration.py +0 -255
  183. mcp_proxy_adapter/tests/performance/__init__.py +0 -3
  184. mcp_proxy_adapter/tests/performance/test_performance.py +0 -189
  185. mcp_proxy_adapter/tests/stubs/__init__.py +0 -10
  186. mcp_proxy_adapter/tests/stubs/echo_command.py +0 -104
  187. mcp_proxy_adapter/tests/test_api_endpoints.py +0 -271
  188. mcp_proxy_adapter/tests/test_api_handlers.py +0 -289
  189. mcp_proxy_adapter/tests/test_base_command.py +0 -123
  190. mcp_proxy_adapter/tests/test_batch_requests.py +0 -117
  191. mcp_proxy_adapter/tests/test_command_registry.py +0 -281
  192. mcp_proxy_adapter/tests/test_config.py +0 -127
  193. mcp_proxy_adapter/tests/test_utils.py +0 -65
  194. mcp_proxy_adapter/tests/unit/__init__.py +0 -3
  195. mcp_proxy_adapter/tests/unit/test_base_command.py +0 -436
  196. mcp_proxy_adapter/tests/unit/test_config.py +0 -217
  197. mcp_proxy_adapter-4.1.1.dist-info/METADATA +0 -200
  198. mcp_proxy_adapter-4.1.1.dist-info/RECORD +0 -110
  199. {mcp_proxy_adapter-4.1.1.dist-info → mcp_proxy_adapter-6.0.1.dist-info}/WHEEL +0 -0
  200. {mcp_proxy_adapter-4.1.1.dist-info → mcp_proxy_adapter-6.0.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,369 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Author: Vasiliy Zdanovskiy
4
+ email: vasilyvz@gmail.com
5
+ Script for generating certificates and tokens for MCP Proxy Adapter configurations.
6
+ Generates all necessary certificates, keys, and tokens based on configuration requirements.
7
+ Uses mcp_security_framework for certificate generation.
8
+ """
9
+ import json
10
+ import os
11
+ import sys
12
+ import argparse
13
+ import subprocess
14
+ from pathlib import Path
15
+ from typing import Dict, Any, List, Optional
16
+ # Import mcp_security_framework
17
+ try:
18
+ from mcp_security_framework.core.cert_manager import CertificateManager
19
+ from mcp_security_framework.schemas.config import CertificateConfig, CAConfig, ServerCertConfig, ClientCertConfig
20
+ from mcp_security_framework.schemas.models import CertificateType
21
+ SECURITY_FRAMEWORK_AVAILABLE = True
22
+ except ImportError:
23
+ SECURITY_FRAMEWORK_AVAILABLE = False
24
+ print("Warning: mcp_security_framework not available, falling back to OpenSSL")
25
+ def generate_ca_certificate(output_dir: str) -> str:
26
+ """
27
+ Generate CA certificate and key using mcp_security_framework.
28
+ Args:
29
+ output_dir: Output directory for certificates
30
+ Returns:
31
+ Path to CA certificate file
32
+ """
33
+ ca_dir = os.path.join(output_dir, "certs")
34
+ os.makedirs(ca_dir, exist_ok=True)
35
+ if SECURITY_FRAMEWORK_AVAILABLE:
36
+ try:
37
+ # Configure CA certificate
38
+ ca_config = CAConfig(
39
+ common_name="MCP Proxy Adapter CA",
40
+ organization="MCP Proxy Adapter",
41
+ organizational_unit="Certificate Authority",
42
+ country="US",
43
+ state="State",
44
+ locality="City",
45
+ validity_years=10, # Используем validity_years вместо validity_days
46
+ key_size=2048,
47
+ hash_algorithm="sha256"
48
+ )
49
+ # Create certificate manager
50
+ cert_config = CertificateConfig(
51
+ cert_storage_path=ca_dir,
52
+ key_storage_path=ca_dir,
53
+ default_validity_days=3650,
54
+ key_size=2048,
55
+ hash_algorithm="sha256"
56
+ )
57
+ cert_manager = CertificateManager(cert_config)
58
+ # Create CA certificate
59
+ cert_pair = cert_manager.create_root_ca(ca_config)
60
+ if cert_pair and cert_pair.certificate_path:
61
+ print(f"✅ Generated CA certificate using mcp_security_framework")
62
+ return cert_pair.certificate_path
63
+ else:
64
+ print(f"❌ Failed to create CA certificate: Invalid certificate pair")
65
+ return None
66
+ except Exception as e:
67
+ print(f"❌ Error creating CA certificate with framework: {e}")
68
+ return None
69
+ else:
70
+ # Fallback to OpenSSL
71
+ ca_key = os.path.join(ca_dir, "ca.key")
72
+ ca_cert = os.path.join(ca_dir, "ca.crt")
73
+ # Generate CA private key
74
+ subprocess.run([
75
+ "openssl", "genrsa", "-out", ca_key, "2048"
76
+ ], check=True, capture_output=True)
77
+ # Generate CA certificate
78
+ subprocess.run([
79
+ "openssl", "req", "-new", "-x509", "-days", "365", "-key", ca_key,
80
+ "-out", ca_cert, "-subj", "/C=US/ST=State/L=City/O=Organization/CN=CA"
81
+ ], check=True, capture_output=True)
82
+ print(f"✅ Generated CA certificate using OpenSSL: {ca_cert}")
83
+ return ca_cert
84
+ def generate_server_certificate(output_dir: str, ca_cert: str) -> tuple[str, str]:
85
+ """
86
+ Generate server certificate and key using mcp_security_framework.
87
+ Args:
88
+ output_dir: Output directory for certificates
89
+ ca_cert: Path to CA certificate
90
+ Returns:
91
+ Tuple of (certificate_path, key_path)
92
+ """
93
+ certs_dir = os.path.join(output_dir, "certs")
94
+ keys_dir = os.path.join(output_dir, "keys")
95
+ os.makedirs(certs_dir, exist_ok=True)
96
+ os.makedirs(keys_dir, exist_ok=True)
97
+ if SECURITY_FRAMEWORK_AVAILABLE:
98
+ try:
99
+ # Find CA key file
100
+ ca_key = None
101
+ if ca_cert.endswith('.crt'):
102
+ ca_key = ca_cert.replace('.crt', '.key')
103
+ elif ca_cert.endswith('.pem'):
104
+ ca_key = ca_cert.replace('.pem', '_key.pem')
105
+ if not os.path.exists(ca_key):
106
+ print(f"❌ CA key file not found: {ca_key}")
107
+ return None, None
108
+ # Configure server certificate
109
+ server_config = ServerCertConfig(
110
+ common_name="localhost",
111
+ organization="MCP Proxy Adapter",
112
+ organizational_unit="Server",
113
+ country="US",
114
+ state="State",
115
+ locality="City",
116
+ validity_days=365,
117
+ key_size=2048,
118
+ hash_algorithm="sha256",
119
+ subject_alt_names=["localhost", "127.0.0.1"], # Используем subject_alt_names вместо san_dns
120
+ ca_cert_path=ca_cert,
121
+ ca_key_path=ca_key
122
+ )
123
+ # Create certificate manager
124
+ cert_config = CertificateConfig(
125
+ cert_storage_path=certs_dir,
126
+ key_storage_path=keys_dir,
127
+ default_validity_days=365,
128
+ key_size=2048,
129
+ hash_algorithm="sha256"
130
+ )
131
+ cert_manager = CertificateManager(cert_config)
132
+ # Create server certificate
133
+ cert_pair = cert_manager.create_server_certificate(server_config)
134
+ if cert_pair and cert_pair.certificate_path and cert_pair.private_key_path:
135
+ print(f"✅ Generated server certificate using mcp_security_framework")
136
+ return (cert_pair.certificate_path, cert_pair.private_key_path)
137
+ else:
138
+ print(f"❌ Failed to create server certificate: Invalid certificate pair")
139
+ return None, None
140
+ except Exception as e:
141
+ print(f"❌ Error creating server certificate with framework: {e}")
142
+ return None, None
143
+ else:
144
+ # Fallback to OpenSSL
145
+ ca_key = ca_cert.replace(".crt", ".key")
146
+ server_key = os.path.join(keys_dir, "server.key")
147
+ server_csr = os.path.join(certs_dir, "server.csr")
148
+ server_cert = os.path.join(certs_dir, "server.crt")
149
+ # Generate server private key
150
+ subprocess.run([
151
+ "openssl", "genrsa", "-out", server_key, "2048"
152
+ ], check=True, capture_output=True)
153
+ # Generate server certificate signing request
154
+ subprocess.run([
155
+ "openssl", "req", "-new", "-key", server_key, "-out", server_csr,
156
+ "-subj", "/C=US/ST=State/L=City/O=Organization/CN=localhost"
157
+ ], check=True, capture_output=True)
158
+ # Sign server certificate with CA
159
+ subprocess.run([
160
+ "openssl", "x509", "-req", "-in", server_csr, "-CA", ca_cert,
161
+ "-CAkey", ca_key, "-CAcreateserial", "-out", server_cert, "-days", "365"
162
+ ], check=True, capture_output=True)
163
+ # Clean up CSR
164
+ os.remove(server_csr)
165
+ print(f"✅ Generated server certificate using OpenSSL: {server_cert}")
166
+ return server_cert, server_key
167
+ def generate_client_certificate(output_dir: str, ca_cert: str, client_name: str = "client",
168
+ roles: List[str] = None, permissions: List[str] = None) -> tuple[str, str]:
169
+ """
170
+ Generate client certificate and key using mcp_security_framework.
171
+ Args:
172
+ output_dir: Output directory for certificates
173
+ ca_cert: Path to CA certificate
174
+ client_name: Name of the client
175
+ roles: List of roles for the client
176
+ permissions: List of permissions for the client
177
+ Returns:
178
+ Tuple of (certificate_path, key_path)
179
+ """
180
+ certs_dir = os.path.join(output_dir, "certs")
181
+ keys_dir = os.path.join(output_dir, "keys")
182
+ os.makedirs(certs_dir, exist_ok=True)
183
+ os.makedirs(keys_dir, exist_ok=True)
184
+ if SECURITY_FRAMEWORK_AVAILABLE:
185
+ try:
186
+ # Find CA key file
187
+ ca_key = None
188
+ if ca_cert.endswith('.crt'):
189
+ ca_key = ca_cert.replace('.crt', '.key')
190
+ elif ca_cert.endswith('.pem'):
191
+ ca_key = ca_cert.replace('.pem', '_key.pem')
192
+ if not os.path.exists(ca_key):
193
+ print(f"❌ CA key file not found: {ca_key}")
194
+ return None, None
195
+ # Configure client certificate
196
+ client_config = ClientCertConfig(
197
+ common_name=f"{client_name}-client",
198
+ organization="MCP Proxy Adapter",
199
+ organizational_unit="Client",
200
+ country="US",
201
+ state="State",
202
+ locality="City",
203
+ validity_days=730,
204
+ key_size=2048,
205
+ hash_algorithm="sha256",
206
+ roles=roles or [],
207
+ permissions=permissions or [],
208
+ ca_cert_path=ca_cert,
209
+ ca_key_path=ca_key
210
+ )
211
+ # Create certificate manager
212
+ cert_config = CertificateConfig(
213
+ cert_storage_path=certs_dir,
214
+ key_storage_path=keys_dir,
215
+ default_validity_days=730,
216
+ key_size=2048,
217
+ hash_algorithm="sha256"
218
+ )
219
+ cert_manager = CertificateManager(cert_config)
220
+ # Create client certificate
221
+ cert_pair = cert_manager.create_client_certificate(client_config)
222
+ if cert_pair and cert_pair.certificate_path and cert_pair.private_key_path:
223
+ print(f"✅ Generated client certificate {client_name} using mcp_security_framework")
224
+ return (cert_pair.certificate_path, cert_pair.private_key_path)
225
+ else:
226
+ print(f"❌ Failed to create client certificate {client_name}: Invalid certificate pair")
227
+ return None, None
228
+ except Exception as e:
229
+ print(f"❌ Error creating client certificate {client_name} with framework: {e}")
230
+ return None, None
231
+ else:
232
+ # Fallback to OpenSSL
233
+ ca_key = ca_cert.replace(".crt", ".key")
234
+ client_key = os.path.join(keys_dir, f"{client_name}.key")
235
+ client_csr = os.path.join(certs_dir, f"{client_name}.csr")
236
+ client_cert = os.path.join(certs_dir, f"{client_name}.crt")
237
+ # Generate client private key
238
+ subprocess.run([
239
+ "openssl", "genrsa", "-out", client_key, "2048"
240
+ ], check=True, capture_output=True)
241
+ # Generate client certificate signing request
242
+ subprocess.run([
243
+ "openssl", "req", "-new", "-key", client_key, "-out", client_csr,
244
+ "-subj", f"/C=US/ST=State/L=City/O=Organization/CN={client_name}-client"
245
+ ], check=True, capture_output=True)
246
+ # Sign client certificate with CA
247
+ subprocess.run([
248
+ "openssl", "x509", "-req", "-in", client_csr, "-CA", ca_cert,
249
+ "-CAkey", ca_key, "-CAcreateserial", "-out", client_cert, "-days", "730"
250
+ ], check=True, capture_output=True)
251
+ # Clean up CSR
252
+ os.remove(client_csr)
253
+ print(f"✅ Generated client certificate {client_name} using OpenSSL: {client_cert}")
254
+ return client_cert, client_key
255
+ def generate_tokens(output_dir: str) -> Dict[str, str]:
256
+ """
257
+ Generate API tokens for different roles.
258
+ Args:
259
+ output_dir: Output directory for tokens
260
+ Returns:
261
+ Dictionary of role -> token mappings
262
+ """
263
+ tokens_dir = os.path.join(output_dir, "tokens")
264
+ os.makedirs(tokens_dir, exist_ok=True)
265
+ tokens = {
266
+ "admin": "test-token-123",
267
+ "user": "user-token-456",
268
+ "readonly": "readonly-token-123",
269
+ "guest": "guest-token-123",
270
+ "proxy": "proxy-token-123"
271
+ }
272
+ # Save tokens to file
273
+ tokens_file = os.path.join(tokens_dir, "tokens.json")
274
+ with open(tokens_file, 'w') as f:
275
+ json.dump(tokens, f, indent=2)
276
+ print(f"✅ Generated tokens: {tokens_file}")
277
+ return tokens
278
+ def generate_roles_config(output_dir: str) -> Dict[str, Any]:
279
+ """
280
+ Generate roles configuration file.
281
+ Args:
282
+ output_dir: Output directory for configs
283
+ Returns:
284
+ Roles configuration dictionary
285
+ """
286
+ roles_config = {
287
+ "admin": {
288
+ "permissions": ["read", "write", "execute", "delete", "admin", "register", "unregister", "heartbeat", "discover"],
289
+ "tokens": []
290
+ },
291
+ "user": {
292
+ "permissions": ["read", "execute", "register", "unregister", "heartbeat", "discover"],
293
+ "tokens": []
294
+ },
295
+ "readonly": {
296
+ "permissions": ["read", "discover"],
297
+ "tokens": []
298
+ },
299
+ "guest": {
300
+ "permissions": ["read", "discover"],
301
+ "tokens": []
302
+ },
303
+ "proxy": {
304
+ "permissions": ["register", "unregister", "heartbeat", "discover"],
305
+ "tokens": []
306
+ }
307
+ }
308
+ # Save roles config to file
309
+ roles_file = os.path.join(output_dir, "roles.json")
310
+ with open(roles_file, 'w') as f:
311
+ json.dump(roles_config, f, indent=2)
312
+ print(f"✅ Generated roles configuration: {roles_file}")
313
+ return roles_config
314
+ def main():
315
+ """Main function for certificate and token generation."""
316
+ parser = argparse.ArgumentParser(description="Generate certificates and tokens")
317
+ parser.add_argument("--output-dir", "-o", default="./certs", help="Output directory")
318
+ parser.add_argument("--framework", action="store_true", help="Use mcp_security_framework")
319
+ args = parser.parse_args()
320
+ print("🔐 Certificate and Token Generation Script")
321
+ print("=" * 50)
322
+ if args.framework and not SECURITY_FRAMEWORK_AVAILABLE:
323
+ print("❌ mcp_security_framework not available")
324
+ return 1
325
+ # Create output directory
326
+ os.makedirs(args.output_dir, exist_ok=True)
327
+ try:
328
+ # 1. Generate CA certificate
329
+ print("\n🔧 Generating CA certificate...")
330
+ ca_cert = generate_ca_certificate(args.output_dir)
331
+ if not ca_cert:
332
+ print("❌ Failed to generate CA certificate")
333
+ return 1
334
+ # 2. Generate server certificate
335
+ print("\n🔧 Generating server certificate...")
336
+ server_cert, server_key = generate_server_certificate(args.output_dir, ca_cert)
337
+ if not server_cert or not server_key:
338
+ print("❌ Failed to generate server certificate")
339
+ return 1
340
+ # 3. Generate client certificates
341
+ print("\n🔧 Generating client certificates...")
342
+ client_configs = [
343
+ ("admin", ["admin"], ["read", "write", "execute", "delete", "admin", "register", "unregister", "heartbeat", "discover"]),
344
+ ("user", ["user"], ["read", "execute", "register", "unregister", "heartbeat", "discover"]),
345
+ ("readonly", ["readonly"], ["read", "discover"]),
346
+ ("guest", ["guest"], ["read", "discover"]),
347
+ ("proxy", ["proxy"], ["register", "unregister", "heartbeat", "discover"])
348
+ ]
349
+ for client_name, roles, permissions in client_configs:
350
+ client_cert, client_key = generate_client_certificate(
351
+ args.output_dir, ca_cert, client_name, roles, permissions
352
+ )
353
+ if not client_cert or not client_key:
354
+ print(f"❌ Failed to generate client certificate {client_name}")
355
+ return 1
356
+ # 4. Generate tokens
357
+ print("\n🔧 Generating tokens...")
358
+ tokens = generate_tokens(args.output_dir)
359
+ # 5. Generate roles configuration
360
+ print("\n🔧 Generating roles configuration...")
361
+ roles_config = generate_roles_config(args.output_dir)
362
+ print("\n🎉 All certificates and tokens generated successfully!")
363
+ print(f"📁 Output directory: {args.output_dir}")
364
+ return 0
365
+ except Exception as e:
366
+ print(f"❌ Error during generation: {e}")
367
+ return 1
368
+ if __name__ == "__main__":
369
+ exit(main())