mcp-proxy-adapter 6.9.43__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 (242) hide show
  1. mcp_proxy_adapter/__init__.py +47 -0
  2. mcp_proxy_adapter/__main__.py +13 -0
  3. mcp_proxy_adapter/api/__init__.py +0 -0
  4. mcp_proxy_adapter/api/app.py +66 -0
  5. mcp_proxy_adapter/api/core/__init__.py +18 -0
  6. mcp_proxy_adapter/api/core/app_factory.py +355 -0
  7. mcp_proxy_adapter/api/core/lifespan_manager.py +55 -0
  8. mcp_proxy_adapter/api/core/registration_context.py +356 -0
  9. mcp_proxy_adapter/api/core/registration_manager.py +266 -0
  10. mcp_proxy_adapter/api/core/registration_tasks.py +84 -0
  11. mcp_proxy_adapter/api/core/ssl_context_factory.py +88 -0
  12. mcp_proxy_adapter/api/handlers.py +181 -0
  13. mcp_proxy_adapter/api/middleware/__init__.py +21 -0
  14. mcp_proxy_adapter/api/middleware/base.py +54 -0
  15. mcp_proxy_adapter/api/middleware/command_permission_middleware.py +73 -0
  16. mcp_proxy_adapter/api/middleware/error_handling.py +76 -0
  17. mcp_proxy_adapter/api/middleware/factory.py +147 -0
  18. mcp_proxy_adapter/api/middleware/logging.py +31 -0
  19. mcp_proxy_adapter/api/middleware/performance.py +51 -0
  20. mcp_proxy_adapter/api/middleware/protocol_middleware.py +140 -0
  21. mcp_proxy_adapter/api/middleware/transport_middleware.py +87 -0
  22. mcp_proxy_adapter/api/middleware/unified_security.py +223 -0
  23. mcp_proxy_adapter/api/middleware/user_info_middleware.py +132 -0
  24. mcp_proxy_adapter/api/openapi/__init__.py +21 -0
  25. mcp_proxy_adapter/api/openapi/command_integration.py +105 -0
  26. mcp_proxy_adapter/api/openapi/openapi_generator.py +40 -0
  27. mcp_proxy_adapter/api/openapi/openapi_registry.py +62 -0
  28. mcp_proxy_adapter/api/openapi/schema_loader.py +116 -0
  29. mcp_proxy_adapter/api/schemas.py +270 -0
  30. mcp_proxy_adapter/api/tool_integration.py +131 -0
  31. mcp_proxy_adapter/api/tools.py +163 -0
  32. mcp_proxy_adapter/cli/__init__.py +12 -0
  33. mcp_proxy_adapter/cli/commands/__init__.py +15 -0
  34. mcp_proxy_adapter/cli/commands/client.py +100 -0
  35. mcp_proxy_adapter/cli/commands/config_generate.py +35 -0
  36. mcp_proxy_adapter/cli/commands/config_validate.py +74 -0
  37. mcp_proxy_adapter/cli/commands/generate.py +259 -0
  38. mcp_proxy_adapter/cli/commands/server.py +174 -0
  39. mcp_proxy_adapter/cli/commands/sets.py +128 -0
  40. mcp_proxy_adapter/cli/commands/testconfig.py +177 -0
  41. mcp_proxy_adapter/cli/examples/__init__.py +8 -0
  42. mcp_proxy_adapter/cli/examples/http_basic.py +82 -0
  43. mcp_proxy_adapter/cli/examples/https_token.py +96 -0
  44. mcp_proxy_adapter/cli/examples/mtls_roles.py +103 -0
  45. mcp_proxy_adapter/cli/main.py +63 -0
  46. mcp_proxy_adapter/cli/parser.py +338 -0
  47. mcp_proxy_adapter/cli/validators.py +231 -0
  48. mcp_proxy_adapter/client/jsonrpc_client/__init__.py +9 -0
  49. mcp_proxy_adapter/client/jsonrpc_client/client.py +42 -0
  50. mcp_proxy_adapter/client/jsonrpc_client/command_api.py +45 -0
  51. mcp_proxy_adapter/client/jsonrpc_client/proxy_api.py +224 -0
  52. mcp_proxy_adapter/client/jsonrpc_client/queue_api.py +60 -0
  53. mcp_proxy_adapter/client/jsonrpc_client/transport.py +108 -0
  54. mcp_proxy_adapter/client/proxy.py +123 -0
  55. mcp_proxy_adapter/commands/__init__.py +66 -0
  56. mcp_proxy_adapter/commands/auth_validation_command.py +69 -0
  57. mcp_proxy_adapter/commands/base.py +389 -0
  58. mcp_proxy_adapter/commands/builtin_commands.py +30 -0
  59. mcp_proxy_adapter/commands/catalog/__init__.py +20 -0
  60. mcp_proxy_adapter/commands/catalog/catalog_loader.py +34 -0
  61. mcp_proxy_adapter/commands/catalog/catalog_manager.py +122 -0
  62. mcp_proxy_adapter/commands/catalog/catalog_syncer.py +149 -0
  63. mcp_proxy_adapter/commands/catalog/command_catalog.py +43 -0
  64. mcp_proxy_adapter/commands/catalog/dependency_manager.py +37 -0
  65. mcp_proxy_adapter/commands/catalog_manager.py +97 -0
  66. mcp_proxy_adapter/commands/cert_monitor_command.py +552 -0
  67. mcp_proxy_adapter/commands/certificate_management_command.py +562 -0
  68. mcp_proxy_adapter/commands/command_registry.py +298 -0
  69. mcp_proxy_adapter/commands/config_command.py +102 -0
  70. mcp_proxy_adapter/commands/dependency_container.py +40 -0
  71. mcp_proxy_adapter/commands/dependency_manager.py +143 -0
  72. mcp_proxy_adapter/commands/echo_command.py +48 -0
  73. mcp_proxy_adapter/commands/health_command.py +142 -0
  74. mcp_proxy_adapter/commands/help_command.py +175 -0
  75. mcp_proxy_adapter/commands/hooks.py +172 -0
  76. mcp_proxy_adapter/commands/key_management_command.py +484 -0
  77. mcp_proxy_adapter/commands/load_command.py +123 -0
  78. mcp_proxy_adapter/commands/plugins_command.py +246 -0
  79. mcp_proxy_adapter/commands/protocol_management_command.py +216 -0
  80. mcp_proxy_adapter/commands/proxy_registration_command.py +319 -0
  81. mcp_proxy_adapter/commands/queue_commands.py +750 -0
  82. mcp_proxy_adapter/commands/registration_status_command.py +76 -0
  83. mcp_proxy_adapter/commands/registry/__init__.py +18 -0
  84. mcp_proxy_adapter/commands/registry/command_info.py +103 -0
  85. mcp_proxy_adapter/commands/registry/command_loader.py +207 -0
  86. mcp_proxy_adapter/commands/registry/command_manager.py +119 -0
  87. mcp_proxy_adapter/commands/registry/command_registry.py +217 -0
  88. mcp_proxy_adapter/commands/reload_command.py +136 -0
  89. mcp_proxy_adapter/commands/result.py +157 -0
  90. mcp_proxy_adapter/commands/role_test_command.py +99 -0
  91. mcp_proxy_adapter/commands/roles_management_command.py +502 -0
  92. mcp_proxy_adapter/commands/security_command.py +472 -0
  93. mcp_proxy_adapter/commands/settings_command.py +113 -0
  94. mcp_proxy_adapter/commands/ssl_setup_command.py +306 -0
  95. mcp_proxy_adapter/commands/token_management_command.py +500 -0
  96. mcp_proxy_adapter/commands/transport_management_command.py +129 -0
  97. mcp_proxy_adapter/commands/unload_command.py +92 -0
  98. mcp_proxy_adapter/config.py +32 -0
  99. mcp_proxy_adapter/core/__init__.py +8 -0
  100. mcp_proxy_adapter/core/app_factory.py +560 -0
  101. mcp_proxy_adapter/core/app_runner.py +318 -0
  102. mcp_proxy_adapter/core/auth_validator.py +508 -0
  103. mcp_proxy_adapter/core/certificate/__init__.py +20 -0
  104. mcp_proxy_adapter/core/certificate/certificate_creator.py +372 -0
  105. mcp_proxy_adapter/core/certificate/certificate_extractor.py +185 -0
  106. mcp_proxy_adapter/core/certificate/certificate_utils.py +249 -0
  107. mcp_proxy_adapter/core/certificate/certificate_validator.py +388 -0
  108. mcp_proxy_adapter/core/certificate/ssl_context_manager.py +65 -0
  109. mcp_proxy_adapter/core/certificate_utils.py +249 -0
  110. mcp_proxy_adapter/core/client.py +608 -0
  111. mcp_proxy_adapter/core/client_manager.py +271 -0
  112. mcp_proxy_adapter/core/client_security.py +411 -0
  113. mcp_proxy_adapter/core/config/__init__.py +18 -0
  114. mcp_proxy_adapter/core/config/config.py +237 -0
  115. mcp_proxy_adapter/core/config/config_factory.py +22 -0
  116. mcp_proxy_adapter/core/config/config_loader.py +66 -0
  117. mcp_proxy_adapter/core/config/feature_manager.py +31 -0
  118. mcp_proxy_adapter/core/config/simple_config.py +116 -0
  119. mcp_proxy_adapter/core/config/simple_config_generator.py +100 -0
  120. mcp_proxy_adapter/core/config/simple_config_validator.py +380 -0
  121. mcp_proxy_adapter/core/config_converter.py +252 -0
  122. mcp_proxy_adapter/core/config_validator.py +211 -0
  123. mcp_proxy_adapter/core/crl_utils.py +362 -0
  124. mcp_proxy_adapter/core/errors.py +276 -0
  125. mcp_proxy_adapter/core/job_manager.py +54 -0
  126. mcp_proxy_adapter/core/logging.py +250 -0
  127. mcp_proxy_adapter/core/mtls_asgi.py +140 -0
  128. mcp_proxy_adapter/core/mtls_asgi_app.py +187 -0
  129. mcp_proxy_adapter/core/mtls_proxy.py +229 -0
  130. mcp_proxy_adapter/core/mtls_server.py +154 -0
  131. mcp_proxy_adapter/core/protocol_manager.py +232 -0
  132. mcp_proxy_adapter/core/proxy/__init__.py +19 -0
  133. mcp_proxy_adapter/core/proxy/auth_manager.py +26 -0
  134. mcp_proxy_adapter/core/proxy/proxy_registration_manager.py +160 -0
  135. mcp_proxy_adapter/core/proxy/registration_client.py +186 -0
  136. mcp_proxy_adapter/core/proxy/ssl_manager.py +101 -0
  137. mcp_proxy_adapter/core/proxy_client.py +184 -0
  138. mcp_proxy_adapter/core/proxy_registration.py +80 -0
  139. mcp_proxy_adapter/core/role_utils.py +103 -0
  140. mcp_proxy_adapter/core/security_adapter.py +343 -0
  141. mcp_proxy_adapter/core/security_factory.py +96 -0
  142. mcp_proxy_adapter/core/security_integration.py +342 -0
  143. mcp_proxy_adapter/core/server_adapter.py +251 -0
  144. mcp_proxy_adapter/core/server_engine.py +217 -0
  145. mcp_proxy_adapter/core/settings.py +260 -0
  146. mcp_proxy_adapter/core/signal_handler.py +107 -0
  147. mcp_proxy_adapter/core/ssl_utils.py +161 -0
  148. mcp_proxy_adapter/core/transport_manager.py +153 -0
  149. mcp_proxy_adapter/core/unified_config_adapter.py +471 -0
  150. mcp_proxy_adapter/core/utils.py +101 -0
  151. mcp_proxy_adapter/core/validation/__init__.py +21 -0
  152. mcp_proxy_adapter/core/validation/config_validator.py +219 -0
  153. mcp_proxy_adapter/core/validation/file_validator.py +131 -0
  154. mcp_proxy_adapter/core/validation/protocol_validator.py +190 -0
  155. mcp_proxy_adapter/core/validation/security_validator.py +140 -0
  156. mcp_proxy_adapter/core/validation/validation_result.py +27 -0
  157. mcp_proxy_adapter/custom_openapi.py +58 -0
  158. mcp_proxy_adapter/examples/__init__.py +16 -0
  159. mcp_proxy_adapter/examples/basic_framework/__init__.py +9 -0
  160. mcp_proxy_adapter/examples/basic_framework/commands/__init__.py +4 -0
  161. mcp_proxy_adapter/examples/basic_framework/hooks/__init__.py +4 -0
  162. mcp_proxy_adapter/examples/basic_framework/main.py +52 -0
  163. mcp_proxy_adapter/examples/bugfix_certificate_config.py +261 -0
  164. mcp_proxy_adapter/examples/cert_manager_bugfix.py +203 -0
  165. mcp_proxy_adapter/examples/check_config.py +413 -0
  166. mcp_proxy_adapter/examples/client_usage_example.py +164 -0
  167. mcp_proxy_adapter/examples/commands/__init__.py +5 -0
  168. mcp_proxy_adapter/examples/config_builder.py +234 -0
  169. mcp_proxy_adapter/examples/config_cli.py +282 -0
  170. mcp_proxy_adapter/examples/create_test_configs.py +174 -0
  171. mcp_proxy_adapter/examples/debug_request_state.py +130 -0
  172. mcp_proxy_adapter/examples/debug_role_chain.py +191 -0
  173. mcp_proxy_adapter/examples/demo_client.py +287 -0
  174. mcp_proxy_adapter/examples/full_application/__init__.py +13 -0
  175. mcp_proxy_adapter/examples/full_application/commands/__init__.py +8 -0
  176. mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +45 -0
  177. mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +52 -0
  178. mcp_proxy_adapter/examples/full_application/commands/echo_command.py +32 -0
  179. mcp_proxy_adapter/examples/full_application/commands/help_command.py +54 -0
  180. mcp_proxy_adapter/examples/full_application/commands/list_command.py +57 -0
  181. mcp_proxy_adapter/examples/full_application/hooks/__init__.py +5 -0
  182. mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +29 -0
  183. mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +27 -0
  184. mcp_proxy_adapter/examples/full_application/main.py +264 -0
  185. mcp_proxy_adapter/examples/full_application/proxy_endpoints.py +81 -0
  186. mcp_proxy_adapter/examples/full_application/run_mtls.py +252 -0
  187. mcp_proxy_adapter/examples/full_application/run_simple.py +152 -0
  188. mcp_proxy_adapter/examples/full_application/test_minimal_server.py +45 -0
  189. mcp_proxy_adapter/examples/full_application/test_server.py +163 -0
  190. mcp_proxy_adapter/examples/full_application/test_simple_server.py +62 -0
  191. mcp_proxy_adapter/examples/generate_config.py +502 -0
  192. mcp_proxy_adapter/examples/proxy_registration_example.py +335 -0
  193. mcp_proxy_adapter/examples/queue_demo_simple.py +632 -0
  194. mcp_proxy_adapter/examples/queue_integration_example.py +578 -0
  195. mcp_proxy_adapter/examples/queue_server_demo.py +82 -0
  196. mcp_proxy_adapter/examples/queue_server_example.py +85 -0
  197. mcp_proxy_adapter/examples/queue_server_simple.py +173 -0
  198. mcp_proxy_adapter/examples/required_certificates.py +208 -0
  199. mcp_proxy_adapter/examples/run_example.py +77 -0
  200. mcp_proxy_adapter/examples/run_full_test_suite.py +619 -0
  201. mcp_proxy_adapter/examples/run_proxy_server.py +153 -0
  202. mcp_proxy_adapter/examples/run_security_tests_fixed.py +435 -0
  203. mcp_proxy_adapter/examples/security_test/__init__.py +18 -0
  204. mcp_proxy_adapter/examples/security_test/auth_manager.py +14 -0
  205. mcp_proxy_adapter/examples/security_test/ssl_context_manager.py +28 -0
  206. mcp_proxy_adapter/examples/security_test/test_client.py +159 -0
  207. mcp_proxy_adapter/examples/security_test/test_result.py +22 -0
  208. mcp_proxy_adapter/examples/security_test_client.py +72 -0
  209. mcp_proxy_adapter/examples/setup/__init__.py +24 -0
  210. mcp_proxy_adapter/examples/setup/certificate_manager.py +215 -0
  211. mcp_proxy_adapter/examples/setup/config_generator.py +12 -0
  212. mcp_proxy_adapter/examples/setup/config_validator.py +118 -0
  213. mcp_proxy_adapter/examples/setup/environment_setup.py +62 -0
  214. mcp_proxy_adapter/examples/setup/test_files_generator.py +10 -0
  215. mcp_proxy_adapter/examples/setup/test_runner.py +89 -0
  216. mcp_proxy_adapter/examples/setup_test_environment.py +235 -0
  217. mcp_proxy_adapter/examples/simple_protocol_test.py +125 -0
  218. mcp_proxy_adapter/examples/test_chk_hostname_automated.py +211 -0
  219. mcp_proxy_adapter/examples/test_config.py +205 -0
  220. mcp_proxy_adapter/examples/test_config_builder.py +110 -0
  221. mcp_proxy_adapter/examples/test_examples.py +308 -0
  222. mcp_proxy_adapter/examples/test_framework_complete.py +267 -0
  223. mcp_proxy_adapter/examples/test_mcp_server.py +187 -0
  224. mcp_proxy_adapter/examples/test_protocol_examples.py +337 -0
  225. mcp_proxy_adapter/examples/universal_client.py +674 -0
  226. mcp_proxy_adapter/examples/update_config_certificates.py +135 -0
  227. mcp_proxy_adapter/examples/validate_generator_compatibility.py +385 -0
  228. mcp_proxy_adapter/examples/validate_generator_compatibility_simple.py +61 -0
  229. mcp_proxy_adapter/integrations/__init__.py +25 -0
  230. mcp_proxy_adapter/integrations/queuemgr_integration.py +462 -0
  231. mcp_proxy_adapter/main.py +313 -0
  232. mcp_proxy_adapter/openapi.py +375 -0
  233. mcp_proxy_adapter/schemas/base_schema.json +114 -0
  234. mcp_proxy_adapter/schemas/openapi_schema.json +314 -0
  235. mcp_proxy_adapter/schemas/roles.json +37 -0
  236. mcp_proxy_adapter/schemas/roles_schema.json +162 -0
  237. mcp_proxy_adapter/version.py +5 -0
  238. mcp_proxy_adapter-6.9.43.dist-info/METADATA +739 -0
  239. mcp_proxy_adapter-6.9.43.dist-info/RECORD +242 -0
  240. mcp_proxy_adapter-6.9.43.dist-info/WHEEL +5 -0
  241. mcp_proxy_adapter-6.9.43.dist-info/entry_points.txt +12 -0
  242. mcp_proxy_adapter-6.9.43.dist-info/top_level.txt +1 -0
@@ -0,0 +1,35 @@
1
+ """
2
+ Author: Vasiliy Zdanovskiy
3
+ email: vasilyvz@gmail.com
4
+
5
+ CLI command: config generate (Simple configuration generator)
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from argparse import Namespace
11
+
12
+ from mcp_proxy_adapter.core.config.simple_config_generator import SimpleConfigGenerator
13
+
14
+
15
+ def config_generate_command(args: Namespace) -> int:
16
+ generator = SimpleConfigGenerator()
17
+ out = generator.generate(
18
+ protocol=args.protocol,
19
+ with_proxy=args.with_proxy,
20
+ out_path=args.out,
21
+ server_host=getattr(args, "server_host", None),
22
+ server_port=getattr(args, "server_port", None),
23
+ server_cert_file=getattr(args, "server_cert_file", None),
24
+ server_key_file=getattr(args, "server_key_file", None),
25
+ server_ca_cert_file=getattr(args, "server_ca_cert_file", None),
26
+ proxy_host=getattr(args, "proxy_host", None),
27
+ proxy_port=getattr(args, "proxy_port", None),
28
+ proxy_cert_file=getattr(args, "proxy_cert_file", None),
29
+ proxy_key_file=getattr(args, "proxy_key_file", None),
30
+ proxy_ca_cert_file=getattr(args, "proxy_ca_cert_file", None),
31
+ )
32
+ print(f"✅ Configuration generated: {out}")
33
+ return 0
34
+
35
+
@@ -0,0 +1,74 @@
1
+ """
2
+ Author: Vasiliy Zdanovskiy
3
+ email: vasilyvz@gmail.com
4
+
5
+ CLI command: config validate (Configuration validation)
6
+ Supports both SimpleConfig and full configuration formats.
7
+ Uses the same ConfigValidator as server startup.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import json
13
+ import sys
14
+ from argparse import Namespace
15
+ from pathlib import Path
16
+
17
+ from mcp_proxy_adapter.core.validation.config_validator import ConfigValidator
18
+
19
+
20
+ def config_validate_command(args: Namespace) -> int:
21
+ """
22
+ Validate configuration file using ConfigValidator.
23
+
24
+ This uses the same validator as server startup to ensure consistency.
25
+ """
26
+ config_file = Path(args.file)
27
+
28
+ if not config_file.exists():
29
+ print(f"❌ Configuration file not found: {config_file}")
30
+ return 1
31
+
32
+ try:
33
+ # Load configuration
34
+ with open(config_file, 'r', encoding='utf-8') as f:
35
+ config_data = json.load(f)
36
+ except json.JSONDecodeError as e:
37
+ print(f"❌ Invalid JSON in configuration file: {e}")
38
+ return 1
39
+ except Exception as e:
40
+ print(f"❌ Failed to load config: {e}")
41
+ return 1
42
+
43
+ # Use the same ConfigValidator as server startup
44
+ validator = ConfigValidator(config_path=str(config_file))
45
+ validator.config_data = config_data
46
+ validation_results = validator.validate_config()
47
+
48
+ # Separate errors and warnings
49
+ errors = [r for r in validation_results if r.level == "error"]
50
+ warnings = [r for r in validation_results if r.level == "warning"]
51
+
52
+ if errors:
53
+ print("❌ Validation failed:")
54
+ for err in errors:
55
+ section_info = f" ({err.section}" + (f".{err.key}" if err.key else "") + ")" if err.section else ""
56
+ print(f" - {err.message}{section_info}")
57
+ if warnings:
58
+ print("\n⚠️ Warnings:")
59
+ for warn in warnings:
60
+ section_info = f" ({warn.section}" + (f".{warn.key}" if warn.key else "") + ")" if warn.section else ""
61
+ print(f" - {warn.message}{section_info}")
62
+ return 1
63
+
64
+ if warnings:
65
+ print("✅ Validation passed with warnings:")
66
+ for warn in warnings:
67
+ section_info = f" ({warn.section}" + (f".{warn.key}" if warn.key else "") + ")" if warn.section else ""
68
+ print(f" ⚠️ {warn.message}{section_info}")
69
+ return 0
70
+
71
+ print("✅ Validation OK")
72
+ return 0
73
+
74
+
@@ -0,0 +1,259 @@
1
+ """
2
+ Generate Command
3
+
4
+ This module implements the generate command for creating configuration files.
5
+
6
+ Author: Vasiliy Zdanovskiy
7
+ email: vasilyvz@gmail.com
8
+ """
9
+
10
+ import json
11
+ from pathlib import Path
12
+ from typing import Dict, Any, Optional
13
+
14
+ # Import the existing config generator
15
+ try:
16
+ from mcp_proxy_adapter.examples.config_builder import generate_complete_config
17
+ from mcp_proxy_adapter.core.config_validator import ConfigValidator
18
+ VALIDATION_AVAILABLE = True
19
+ except ImportError:
20
+ VALIDATION_AVAILABLE = False
21
+ print("Warning: Configuration validation not available. Install the package to enable validation.")
22
+
23
+
24
+ class GenerateCommand:
25
+ """Command for generating configuration files."""
26
+
27
+ def __init__(self):
28
+ """Initialize the generate command."""
29
+ pass
30
+
31
+ def execute(self, args: Dict[str, Any]) -> int:
32
+ """
33
+ Execute the generate command.
34
+
35
+ Args:
36
+ args: Parsed command arguments
37
+
38
+ Returns:
39
+ Exit code (0 for success, 1 for error)
40
+ """
41
+ try:
42
+ # Handle special cases
43
+ if args.get('all'):
44
+ return self._generate_all_configs(args)
45
+
46
+ # Generate single configuration
47
+ return self._generate_single_config(args)
48
+
49
+ except Exception as e:
50
+ print(f"❌ Error generating configuration: {e}")
51
+ return 1
52
+
53
+ def _generate_single_config(self, args: Dict[str, Any]) -> int:
54
+ """Generate a single configuration file."""
55
+ # Create configuration
56
+ config = self._create_config_from_args(args)
57
+
58
+ # Save configuration
59
+ if args.get('stdout'):
60
+ # Output to stdout
61
+ print(json.dumps(config, indent=2, ensure_ascii=False))
62
+ else:
63
+ # Save to file
64
+ config_file = self._save_config(config, args)
65
+ print(f"✅ Configuration saved to: {config_file}")
66
+
67
+ return 0
68
+
69
+ def _generate_all_configs(self, args: Dict[str, Any]) -> int:
70
+ """Generate all standard configurations."""
71
+ print("🔧 Generating MCP Proxy Adapter configurations...")
72
+ print("=" * 60)
73
+
74
+ # Define all standard configurations
75
+ configs = [
76
+ # HTTP configurations
77
+ ("http", False, False, 20000),
78
+ ("http", True, True, 20001), # token + roles
79
+ ("http", True, False, 20002), # token only
80
+
81
+ # HTTPS configurations
82
+ ("https", False, False, 20003),
83
+ ("https", True, True, 20004), # token + roles
84
+ ("https", True, False, 20005), # token only
85
+
86
+ # mTLS configurations
87
+ ("mtls", False, False, 20006),
88
+ ("mtls", False, True, 20007), # roles only (from certificate)
89
+ ]
90
+
91
+ generated_files = []
92
+
93
+ for protocol, token, roles, port in configs:
94
+ # Create configuration name
95
+ name_parts = [protocol]
96
+ if token:
97
+ name_parts.append("token")
98
+ if roles:
99
+ name_parts.append("roles")
100
+
101
+ config_name = "_".join(name_parts)
102
+
103
+ # Create args for this configuration
104
+ config_args = args.copy()
105
+ config_args.update({
106
+ 'protocol': protocol,
107
+ 'token': token,
108
+ 'roles': roles,
109
+ 'port': port
110
+ })
111
+
112
+ # Generate configuration
113
+ config = self._create_config_from_args(config_args)
114
+
115
+ # Save configuration
116
+ config_file = self._save_config(config, config_args, config_name)
117
+ generated_files.append(config_file)
118
+
119
+ print(f"✅ Created {config_name}.json (port {port})")
120
+
121
+ # Create roles.json file if any role-based configs were generated
122
+ self._create_roles_file(args.get('output_dir', './configs'))
123
+
124
+ print(f"\n🎉 Generated {len(generated_files)} configurations in {args.get('output_dir', './configs')}/")
125
+ print("\n📋 Generated configurations:")
126
+ for config_file in generated_files:
127
+ print(f" - {config_file.name}")
128
+
129
+ return 0
130
+
131
+ def _create_config_from_args(self, args: Dict[str, Any]) -> Dict[str, Any]:
132
+ """Create configuration dictionary from arguments."""
133
+ # Start with basic configuration
134
+ config = generate_complete_config(
135
+ args.get('host', '127.0.0.1'),
136
+ args.get('port', 8000)
137
+ )
138
+
139
+ # Set protocol
140
+ config["server"]["protocol"] = args.get('protocol', 'http')
141
+
142
+ # Configure SSL based on protocol
143
+ if args.get('protocol') == 'https':
144
+ config["ssl"]["enabled"] = True
145
+ config["ssl"]["cert_file"] = f"{args.get('cert_dir', './certs')}/server.crt"
146
+ config["ssl"]["key_file"] = f"{args.get('key_dir', './keys')}/server.key"
147
+ elif args.get('protocol') == 'mtls':
148
+ config["ssl"]["enabled"] = True
149
+ config["ssl"]["cert_file"] = f"{args.get('cert_dir', './certs')}/server.crt"
150
+ config["ssl"]["key_file"] = f"{args.get('key_dir', './keys')}/server.key"
151
+ config["ssl"]["ca_cert"] = f"{args.get('cert_dir', './certs')}/ca.crt"
152
+ config["transport"]["verify_client"] = True
153
+
154
+ # Configure security if token authentication is enabled
155
+ if args.get('token'):
156
+ config["security"]["enabled"] = True
157
+ config["security"]["tokens"] = {
158
+ "admin": "admin-secret-key",
159
+ "user": "user-secret-key",
160
+ "readonly": "readonly-secret-key"
161
+ }
162
+
163
+ if args.get('roles'):
164
+ config["security"]["roles"] = {
165
+ "admin": ["read", "write", "delete", "admin"],
166
+ "user": ["read", "write"],
167
+ "readonly": ["read"]
168
+ }
169
+ config["security"]["roles_file"] = f"{args.get('output_dir', './configs')}/roles.json"
170
+ config["roles"]["enabled"] = True
171
+ config["roles"]["config_file"] = f"{args.get('output_dir', './configs')}/roles.json"
172
+ elif args.get('roles') and args.get('protocol') == 'mtls':
173
+ # For mTLS, roles can be enabled without tokens (from certificate)
174
+ config["roles"]["enabled"] = True
175
+ config["roles"]["config_file"] = f"{args.get('output_dir', './configs')}/roles.json"
176
+
177
+ # Configure proxy registration if enabled
178
+ if args.get('proxy_url'):
179
+ config["proxy_registration"]["enabled"] = True
180
+ config["proxy_registration"]["proxy_url"] = args['proxy_url']
181
+ config["proxy_registration"]["server_id"] = args.get('server_id', 'mcp-proxy-adapter')
182
+
183
+ return config
184
+
185
+ def _save_config(self, config: Dict[str, Any], args: Dict[str, Any], filename: Optional[str] = None) -> Path:
186
+ """Save configuration to file with optional validation."""
187
+ output_dir = Path(args.get('output_dir', './configs'))
188
+ output_dir.mkdir(parents=True, exist_ok=True)
189
+
190
+ # Determine filename
191
+ if filename:
192
+ config_name = filename
193
+ elif args.get('output'):
194
+ config_name = args['output']
195
+ else:
196
+ # Generate filename from arguments
197
+ name_parts = [args.get('protocol', 'http')]
198
+ if args.get('token'):
199
+ name_parts.append("token")
200
+ if args.get('roles'):
201
+ name_parts.append("roles")
202
+ config_name = "_".join(name_parts)
203
+
204
+ config_file = output_dir / f"{config_name}.json"
205
+
206
+ # Save configuration
207
+ with open(config_file, 'w', encoding='utf-8') as f:
208
+ json.dump(config, f, indent=2, ensure_ascii=False)
209
+
210
+ # Validate configuration if requested and validation is available
211
+ if not args.get('no_validate') and VALIDATION_AVAILABLE:
212
+ print(f"🔍 Validating configuration: {config_file}")
213
+ validator = ConfigValidator()
214
+ validator.config_data = config
215
+ results = validator.validate_config()
216
+
217
+ if results:
218
+ print("⚠️ Validation issues found:")
219
+ for result in results:
220
+ level_symbol = "❌" if result.level == "error" else "⚠️" if result.level == "warning" else "ℹ️"
221
+ print(f" {level_symbol} {result.message}")
222
+ if hasattr(result, 'suggestion') and result.suggestion:
223
+ print(f" Suggestion: {result.suggestion}")
224
+ else:
225
+ print("✅ Configuration validation passed!")
226
+
227
+ return config_file
228
+
229
+ def _create_roles_file(self, output_dir: str) -> None:
230
+ """Create roles.json file for role-based configurations."""
231
+ roles_config = {
232
+ "enabled": True,
233
+ "default_policy": {
234
+ "deny_by_default": False,
235
+ "require_role_match": False,
236
+ "case_sensitive": False,
237
+ "allow_wildcard": False
238
+ },
239
+ "roles": {
240
+ "admin": ["read", "write", "delete", "admin"],
241
+ "user": ["read", "write"],
242
+ "readonly": ["read"],
243
+ "guest": ["read"],
244
+ "proxy": ["read", "write"]
245
+ },
246
+ "permissions": {
247
+ "read": ["GET"],
248
+ "write": ["POST", "PUT", "PATCH"],
249
+ "delete": ["DELETE"],
250
+ "admin": ["*"]
251
+ }
252
+ }
253
+
254
+ roles_file = Path(output_dir) / "roles.json"
255
+ with open(roles_file, 'w', encoding='utf-8') as f:
256
+ json.dump(roles_config, f, indent=2, ensure_ascii=False)
257
+ print(f"✅ Created roles.json")
258
+
259
+
@@ -0,0 +1,174 @@
1
+ """
2
+ Server Command
3
+
4
+ This module implements the server command for starting MCP Proxy Adapter server.
5
+
6
+ Author: Vasiliy Zdanovskiy
7
+ email: vasilyvz@gmail.com
8
+ """
9
+
10
+ import json
11
+ from pathlib import Path
12
+ from typing import Dict, Any
13
+
14
+ try:
15
+ from mcp_proxy_adapter.core.validation.config_validator import ConfigValidator
16
+ from mcp_proxy_adapter.core.server_adapter import UnifiedServerRunner
17
+ from mcp_proxy_adapter.api.app import create_app
18
+ VALIDATION_AVAILABLE = True
19
+ except ImportError:
20
+ VALIDATION_AVAILABLE = False
21
+
22
+
23
+ class ServerCommand:
24
+ """Command for starting the MCP Proxy Adapter server."""
25
+
26
+ def __init__(self):
27
+ """Initialize the server command."""
28
+ pass
29
+
30
+ def execute(self, args: Dict[str, Any]) -> int:
31
+ """
32
+ Execute the server command.
33
+
34
+ Args:
35
+ args: Parsed command arguments
36
+
37
+ Returns:
38
+ Exit code (0 for success, 1 for error)
39
+ """
40
+ config_file = args['config']
41
+ no_validate = args.get('no_validate', False)
42
+
43
+ try:
44
+ # Load configuration
45
+ print(f"🔍 Loading configuration from: {config_file}")
46
+ with open(config_file, 'r', encoding='utf-8') as f:
47
+ config = json.load(f)
48
+
49
+ # Validate configuration if not disabled
50
+ if not no_validate and VALIDATION_AVAILABLE:
51
+ print("🔍 Validating configuration...")
52
+ if not self._validate_config(config, config_file):
53
+ print("❌ Configuration validation failed. Server not started.")
54
+ return 1
55
+ print("✅ Configuration validation passed!")
56
+ elif no_validate:
57
+ print("⚠️ Configuration validation skipped (--no-validate)")
58
+ else:
59
+ print("⚠️ Configuration validation not available")
60
+
61
+ # Override configuration with command line arguments
62
+ if args.get('port'):
63
+ config['server']['port'] = args['port']
64
+ print(f"🔧 Overriding port to: {args['port']}")
65
+
66
+ if args.get('host'):
67
+ config['server']['host'] = args['host']
68
+ print(f"🔧 Overriding host to: {args['host']}")
69
+
70
+ # Create and start server
71
+ print("🚀 Starting MCP Proxy Adapter server...")
72
+ self._start_server(config, args)
73
+
74
+ except FileNotFoundError:
75
+ print(f"❌ Configuration file not found: {config_file}")
76
+ return 1
77
+ except json.JSONDecodeError as e:
78
+ print(f"❌ Invalid JSON in configuration file: {e}")
79
+ return 1
80
+ except Exception as e:
81
+ print(f"❌ Error starting server: {e}")
82
+ return 1
83
+
84
+ def _validate_config(self, config: Dict[str, Any], config_file: str) -> bool:
85
+ """
86
+ Validate configuration using ConfigValidator.
87
+
88
+ Args:
89
+ config: Configuration dictionary
90
+ config_file: Path to configuration file
91
+
92
+ Returns:
93
+ True if configuration is valid, False otherwise
94
+ """
95
+ try:
96
+ validator = ConfigValidator()
97
+ validator.config_data = config
98
+ results = validator.validate_config()
99
+
100
+ # Check for errors
101
+ errors = [r for r in results if r.level == "error"]
102
+ warnings = [r for r in results if r.level == "warning"]
103
+
104
+ if errors:
105
+ print("❌ Configuration validation errors:")
106
+ for error in errors:
107
+ print(f" • {error.message}")
108
+ if hasattr(error, 'suggestion') and error.suggestion:
109
+ print(f" → {error.suggestion}")
110
+ return False
111
+
112
+ if warnings:
113
+ print("⚠️ Configuration validation warnings:")
114
+ for warning in warnings:
115
+ print(f" • {warning.message}")
116
+ if hasattr(warning, 'suggestion') and warning.suggestion:
117
+ print(f" → {warning.suggestion}")
118
+
119
+ return True
120
+
121
+ except Exception as e:
122
+ print(f"❌ Error during configuration validation: {e}")
123
+ return False
124
+
125
+ def _start_server(self, config: Dict[str, Any], args: Dict[str, Any]) -> None:
126
+ """
127
+ Start the MCP Proxy Adapter server.
128
+
129
+ Args:
130
+ config: Server configuration
131
+ args: Command line arguments
132
+ """
133
+ try:
134
+ # Create ASGI application
135
+ app = create_app(config)
136
+
137
+ # Prepare server configuration
138
+ server_config = {
139
+ 'host': config['server']['host'],
140
+ 'port': config['server']['port'],
141
+ 'log_level': config['server'].get('log_level', 'INFO'),
142
+ 'reload': args.get('reload', False)
143
+ }
144
+
145
+ # Add SSL configuration if present
146
+ if 'ssl' in config and config['ssl'].get('enabled'):
147
+ server_config.update({
148
+ 'certfile': config['ssl'].get('cert_file'),
149
+ 'keyfile': config['ssl'].get('key_file'),
150
+ 'ca_certs': config['ssl'].get('ca_cert'),
151
+ 'verify_mode': 'CERT_REQUIRED' if config.get('transport', {}).get('verify_client') else 'CERT_NONE'
152
+ })
153
+
154
+ # Start server
155
+ print(f"🌐 Server starting on {server_config['host']}:{server_config['port']}")
156
+ print(f"📋 Protocol: {config['server']['protocol']}")
157
+ print(f"🔐 Security: {'Enabled' if config.get('security', {}).get('enabled') else 'Disabled'}")
158
+ print(f"🔑 Authentication: {'Token-based' if config.get('security', {}).get('tokens') else 'Certificate-based' if config['server']['protocol'] == 'mtls' else 'None'}")
159
+ print(f"👥 Roles: {'Enabled' if config.get('roles', {}).get('enabled') else 'Disabled'}")
160
+ print("=" * 60)
161
+
162
+ # Use UnifiedServerRunner to start the server
163
+ runner = UnifiedServerRunner()
164
+ runner.run_server(app, server_config)
165
+
166
+ except ImportError as e:
167
+ print(f"❌ Missing required dependencies: {e}")
168
+ print("💡 Install required packages: pip install hypercorn")
169
+ raise
170
+ except Exception as e:
171
+ print(f"❌ Failed to start server: {e}")
172
+ raise
173
+
174
+
@@ -0,0 +1,128 @@
1
+ """
2
+ Sets Command
3
+
4
+ This module implements the sets command for generating configurations using predefined sets.
5
+
6
+ Author: Vasiliy Zdanovskiy
7
+ email: vasilyvz@gmail.com
8
+ """
9
+
10
+ import json
11
+ from pathlib import Path
12
+ from typing import Dict, Any
13
+
14
+ from mcp_proxy_adapter.core.config.simple_config import (
15
+ SimpleConfig,
16
+ SimpleConfigModel,
17
+ ServerConfig,
18
+ ProxyClientConfig,
19
+ AuthConfig,
20
+ )
21
+
22
+
23
+ class SetsCommand:
24
+ """Command for generating configurations using predefined sets."""
25
+
26
+ def __init__(self):
27
+ """Initialize the sets command."""
28
+ pass
29
+
30
+ def execute(self, args: Dict[str, Any]) -> int:
31
+ """
32
+ Execute the sets command.
33
+
34
+ Args:
35
+ args: Parsed command arguments
36
+
37
+ Returns:
38
+ Exit code (0 for success, 1 for error)
39
+ """
40
+ set_name = args.get('set_name')
41
+
42
+ if not set_name:
43
+ print("❌ No set specified. Use: sets {http,https,mtls}")
44
+ return 1
45
+
46
+ try:
47
+ # Generate configuration based on set
48
+ config_path = self._create_config_from_set(set_name, args)
49
+
50
+ print(f"✅ {set_name.upper()} configuration saved to: {config_path}")
51
+ return 0
52
+
53
+ except Exception as e:
54
+ print(f"❌ Error generating {set_name} configuration: {e}")
55
+ return 1
56
+
57
+ def _create_config_from_set(self, set_name: str, args: Dict[str, Any]) -> Path:
58
+ """
59
+ Create configuration based on the specified set.
60
+
61
+ Args:
62
+ set_name: Name of the configuration set
63
+ args: Command arguments
64
+
65
+ Returns:
66
+ Path to saved configuration file
67
+ """
68
+ host = args.get('host', '127.0.0.1')
69
+ port = int(args.get('port', 8000))
70
+ protocol = set_name
71
+
72
+ # Build server config compatible with SimpleConfig
73
+ server = ServerConfig(host=host, port=port, protocol=protocol)
74
+ cert_dir = Path(args.get('cert_dir') or './certs')
75
+ key_dir = Path(args.get('key_dir') or './keys')
76
+ if protocol in ('https', 'mtls'):
77
+ # Prefer test-server.* filenames if present, otherwise fallback to server.*
78
+ cert_file = cert_dir / 'test-server.crt'
79
+ key_file = key_dir / 'test-server.key'
80
+ if not cert_file.exists():
81
+ cert_file = cert_dir / 'server.crt'
82
+ if not key_file.exists():
83
+ key_file = key_dir / 'server.key'
84
+ server.cert_file = str(cert_file)
85
+ server.key_file = str(key_file)
86
+ if protocol == 'mtls':
87
+ # CA file path is expected by validator; try ca/ca.crt relative to provided cert_dir
88
+ ca_candidate = cert_dir.parent / 'ca' / 'ca.crt'
89
+ if not ca_candidate.exists():
90
+ ca_candidate = cert_dir / 'ca.crt'
91
+ server.ca_cert_file = str(ca_candidate)
92
+
93
+ # Proxy client (disabled by default here)
94
+ proxy = ProxyClientConfig(enabled=False)
95
+
96
+ # Auth config based on modifiers
97
+ use_token = 'token' in (args.get('modifiers') or []) or bool(args.get('token'))
98
+ use_roles = 'roles' in (args.get('modifiers') or []) or bool(args.get('roles'))
99
+ # If roles are requested, token must be enabled to satisfy validator
100
+ if use_roles and not use_token:
101
+ use_token = True
102
+ tokens = {
103
+ 'admin': ['read', 'write', 'delete', 'admin'],
104
+ } if use_token else {}
105
+ roles = {
106
+ 'admin': ['read', 'write', 'delete', 'admin'],
107
+ 'user': ['read', 'write'],
108
+ } if use_roles else {}
109
+ auth = AuthConfig(use_token=use_token, use_roles=use_roles, tokens=tokens, roles=roles)
110
+
111
+ # Save using SimpleConfig
112
+ model = SimpleConfigModel(server=server, proxy_client=proxy, auth=auth)
113
+ out_dir = Path(args.get('output_dir', './configs'))
114
+ out_dir.mkdir(parents=True, exist_ok=True)
115
+ name_parts = [set_name]
116
+ if use_token and set_name in ['http', 'https']:
117
+ name_parts.append('token')
118
+ if use_roles:
119
+ name_parts.append('roles')
120
+ filename = args.get('output') or "_".join(name_parts)
121
+ out_path = out_dir / f"{filename}.json"
122
+
123
+ cfg = SimpleConfig(str(out_path))
124
+ cfg.model = model
125
+ cfg.save()
126
+ return out_path
127
+
128
+