mcp-proxy-adapter 4.1.1__py3-none-any.whl → 6.0.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 (101) hide show
  1. mcp_proxy_adapter/__main__.py +12 -0
  2. mcp_proxy_adapter/api/app.py +138 -11
  3. mcp_proxy_adapter/api/handlers.py +16 -1
  4. mcp_proxy_adapter/api/middleware/__init__.py +30 -29
  5. mcp_proxy_adapter/api/middleware/auth_adapter.py +235 -0
  6. mcp_proxy_adapter/api/middleware/error_handling.py +9 -0
  7. mcp_proxy_adapter/api/middleware/factory.py +219 -0
  8. mcp_proxy_adapter/api/middleware/logging.py +32 -6
  9. mcp_proxy_adapter/api/middleware/mtls_adapter.py +305 -0
  10. mcp_proxy_adapter/api/middleware/mtls_middleware.py +296 -0
  11. mcp_proxy_adapter/api/middleware/protocol_middleware.py +135 -0
  12. mcp_proxy_adapter/api/middleware/rate_limit_adapter.py +241 -0
  13. mcp_proxy_adapter/api/middleware/roles_adapter.py +365 -0
  14. mcp_proxy_adapter/api/middleware/roles_middleware.py +381 -0
  15. mcp_proxy_adapter/api/middleware/security.py +376 -0
  16. mcp_proxy_adapter/api/middleware/token_auth_middleware.py +261 -0
  17. mcp_proxy_adapter/api/middleware/transport_middleware.py +122 -0
  18. mcp_proxy_adapter/commands/__init__.py +13 -4
  19. mcp_proxy_adapter/commands/auth_validation_command.py +408 -0
  20. mcp_proxy_adapter/commands/base.py +61 -30
  21. mcp_proxy_adapter/commands/builtin_commands.py +89 -0
  22. mcp_proxy_adapter/commands/catalog_manager.py +838 -0
  23. mcp_proxy_adapter/commands/cert_monitor_command.py +620 -0
  24. mcp_proxy_adapter/commands/certificate_management_command.py +608 -0
  25. mcp_proxy_adapter/commands/command_registry.py +703 -354
  26. mcp_proxy_adapter/commands/dependency_manager.py +245 -0
  27. mcp_proxy_adapter/commands/health_command.py +7 -0
  28. mcp_proxy_adapter/commands/hooks.py +200 -167
  29. mcp_proxy_adapter/commands/key_management_command.py +506 -0
  30. mcp_proxy_adapter/commands/load_command.py +176 -0
  31. mcp_proxy_adapter/commands/plugins_command.py +235 -0
  32. mcp_proxy_adapter/commands/protocol_management_command.py +232 -0
  33. mcp_proxy_adapter/commands/proxy_registration_command.py +268 -0
  34. mcp_proxy_adapter/commands/reload_command.py +48 -50
  35. mcp_proxy_adapter/commands/result.py +1 -0
  36. mcp_proxy_adapter/commands/roles_management_command.py +697 -0
  37. mcp_proxy_adapter/commands/ssl_setup_command.py +483 -0
  38. mcp_proxy_adapter/commands/token_management_command.py +529 -0
  39. mcp_proxy_adapter/commands/transport_management_command.py +144 -0
  40. mcp_proxy_adapter/commands/unload_command.py +158 -0
  41. mcp_proxy_adapter/config.py +99 -2
  42. mcp_proxy_adapter/core/auth_validator.py +606 -0
  43. mcp_proxy_adapter/core/certificate_utils.py +827 -0
  44. mcp_proxy_adapter/core/config_converter.py +405 -0
  45. mcp_proxy_adapter/core/config_validator.py +218 -0
  46. mcp_proxy_adapter/core/logging.py +11 -0
  47. mcp_proxy_adapter/core/protocol_manager.py +226 -0
  48. mcp_proxy_adapter/core/proxy_registration.py +270 -0
  49. mcp_proxy_adapter/core/role_utils.py +426 -0
  50. mcp_proxy_adapter/core/security_adapter.py +373 -0
  51. mcp_proxy_adapter/core/security_factory.py +239 -0
  52. mcp_proxy_adapter/core/settings.py +1 -0
  53. mcp_proxy_adapter/core/ssl_utils.py +233 -0
  54. mcp_proxy_adapter/core/transport_manager.py +292 -0
  55. mcp_proxy_adapter/custom_openapi.py +22 -11
  56. mcp_proxy_adapter/examples/basic_server/config.json +58 -23
  57. mcp_proxy_adapter/examples/basic_server/config_all_protocols.json +54 -0
  58. mcp_proxy_adapter/examples/basic_server/config_http.json +70 -0
  59. mcp_proxy_adapter/examples/basic_server/config_http_only.json +52 -0
  60. mcp_proxy_adapter/examples/basic_server/config_https.json +58 -0
  61. mcp_proxy_adapter/examples/basic_server/config_mtls.json +58 -0
  62. mcp_proxy_adapter/examples/basic_server/config_ssl.json +46 -0
  63. mcp_proxy_adapter/examples/basic_server/server.py +12 -1
  64. mcp_proxy_adapter/examples/custom_commands/__init__.py +1 -1
  65. mcp_proxy_adapter/examples/custom_commands/advanced_hooks.py +339 -23
  66. mcp_proxy_adapter/examples/custom_commands/auto_commands/test_command.py +105 -0
  67. mcp_proxy_adapter/examples/custom_commands/catalog/commands/test_command.py +129 -0
  68. mcp_proxy_adapter/examples/custom_commands/config.json +101 -18
  69. mcp_proxy_adapter/examples/custom_commands/config_all_protocols.json +46 -0
  70. mcp_proxy_adapter/examples/custom_commands/config_https_only.json +46 -0
  71. mcp_proxy_adapter/examples/custom_commands/config_https_transport.json +33 -0
  72. mcp_proxy_adapter/examples/custom_commands/config_mtls_only.json +46 -0
  73. mcp_proxy_adapter/examples/custom_commands/config_mtls_transport.json +33 -0
  74. mcp_proxy_adapter/examples/custom_commands/config_single_transport.json +33 -0
  75. mcp_proxy_adapter/examples/custom_commands/full_help_response.json +1 -0
  76. mcp_proxy_adapter/examples/custom_commands/generated_openapi.json +629 -0
  77. mcp_proxy_adapter/examples/custom_commands/get_openapi.py +103 -0
  78. mcp_proxy_adapter/examples/custom_commands/loadable_commands/test_ignored.py +129 -0
  79. mcp_proxy_adapter/examples/custom_commands/proxy_connection_manager.py +278 -0
  80. mcp_proxy_adapter/examples/custom_commands/server.py +92 -68
  81. mcp_proxy_adapter/examples/custom_commands/simple_openapi_server.py +75 -0
  82. mcp_proxy_adapter/examples/custom_commands/start_server_with_proxy_manager.py +299 -0
  83. mcp_proxy_adapter/examples/custom_commands/start_server_with_registration.py +278 -0
  84. mcp_proxy_adapter/examples/custom_commands/test_openapi.py +27 -0
  85. mcp_proxy_adapter/examples/custom_commands/test_registry.py +23 -0
  86. mcp_proxy_adapter/examples/custom_commands/test_simple.py +19 -0
  87. mcp_proxy_adapter/examples/custom_project_example/README.md +103 -0
  88. mcp_proxy_adapter/examples/custom_project_example/README_EN.md +103 -0
  89. mcp_proxy_adapter/examples/simple_custom_commands/README.md +149 -0
  90. mcp_proxy_adapter/examples/simple_custom_commands/README_EN.md +149 -0
  91. mcp_proxy_adapter/main.py +175 -0
  92. mcp_proxy_adapter/schemas/roles_schema.json +162 -0
  93. mcp_proxy_adapter/tests/unit/test_config.py +53 -0
  94. mcp_proxy_adapter/version.py +1 -1
  95. {mcp_proxy_adapter-4.1.1.dist-info → mcp_proxy_adapter-6.0.0.dist-info}/METADATA +2 -1
  96. mcp_proxy_adapter-6.0.0.dist-info/RECORD +179 -0
  97. mcp_proxy_adapter/commands/reload_settings_command.py +0 -125
  98. mcp_proxy_adapter-4.1.1.dist-info/RECORD +0 -110
  99. {mcp_proxy_adapter-4.1.1.dist-info → mcp_proxy_adapter-6.0.0.dist-info}/WHEEL +0 -0
  100. {mcp_proxy_adapter-4.1.1.dist-info → mcp_proxy_adapter-6.0.0.dist-info}/licenses/LICENSE +0 -0
  101. {mcp_proxy_adapter-4.1.1.dist-info → mcp_proxy_adapter-6.0.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,245 @@
1
+ """
2
+ Dependency management system for remote plugins.
3
+
4
+ This module handles automatic installation and verification of plugin dependencies
5
+ using pip and other package management tools.
6
+ """
7
+
8
+ import subprocess
9
+ import sys
10
+ import importlib
11
+ import pkg_resources
12
+ from typing import List, Dict, Any, Optional, Tuple
13
+ from pathlib import Path
14
+
15
+ from mcp_proxy_adapter.core.logging import logger
16
+
17
+
18
+ class DependencyManager:
19
+ """
20
+ Manages plugin dependencies installation and verification.
21
+ """
22
+
23
+ def __init__(self):
24
+ """Initialize dependency manager."""
25
+ self._installed_packages: Dict[str, str] = {}
26
+ self._load_installed_packages()
27
+
28
+ def _load_installed_packages(self) -> None:
29
+ """Load list of currently installed packages."""
30
+ try:
31
+ installed = pkg_resources.working_set
32
+ for dist in installed:
33
+ self._installed_packages[dist.project_name.lower()] = dist.version
34
+ except Exception as e:
35
+ logger.warning(f"Failed to load installed packages: {e}")
36
+
37
+ def check_dependencies(self, dependencies: List[str]) -> Tuple[bool, List[str], List[str]]:
38
+ """
39
+ Check if dependencies are satisfied.
40
+
41
+ Args:
42
+ dependencies: List of dependency names
43
+
44
+ Returns:
45
+ Tuple of (all_satisfied, missing_deps, installed_deps)
46
+ """
47
+ if not dependencies:
48
+ return True, [], []
49
+
50
+ missing_deps = []
51
+ installed_deps = []
52
+
53
+ for dep in dependencies:
54
+ if self._is_dependency_satisfied(dep):
55
+ installed_deps.append(dep)
56
+ else:
57
+ missing_deps.append(dep)
58
+
59
+ all_satisfied = len(missing_deps) == 0
60
+ return all_satisfied, missing_deps, installed_deps
61
+
62
+ def _is_dependency_satisfied(self, dependency: str) -> bool:
63
+ """
64
+ Check if a single dependency is satisfied.
65
+
66
+ Args:
67
+ dependency: Dependency name or spec
68
+
69
+ Returns:
70
+ True if dependency is satisfied, False otherwise
71
+ """
72
+ # Try to import the module
73
+ try:
74
+ importlib.import_module(dependency)
75
+ return True
76
+ except ImportError:
77
+ pass
78
+
79
+ # Check if it's installed as a package
80
+ try:
81
+ pkg_resources.require(dependency)
82
+ return True
83
+ except (pkg_resources.DistributionNotFound, pkg_resources.VersionConflict):
84
+ pass
85
+
86
+ # Check installed packages cache
87
+ dep_name = dependency.split('==')[0].split('>=')[0].split('<=')[0].split('!=')[0].split('~=')[0]
88
+ if dep_name.lower() in self._installed_packages:
89
+ return True
90
+
91
+ return False
92
+
93
+ def install_dependencies(self, dependencies: List[str], user_install: bool = False) -> Tuple[bool, List[str], List[str]]:
94
+ """
95
+ Install dependencies using pip.
96
+
97
+ Args:
98
+ dependencies: List of dependency names to install
99
+ user_install: Whether to install for current user only
100
+
101
+ Returns:
102
+ Tuple of (success, installed_deps, failed_deps)
103
+ """
104
+ if not dependencies:
105
+ return True, [], []
106
+
107
+ installed_deps = []
108
+ failed_deps = []
109
+
110
+ for dep in dependencies:
111
+ try:
112
+ if self._install_single_dependency(dep, user_install):
113
+ installed_deps.append(dep)
114
+ logger.info(f"Successfully installed dependency: {dep}")
115
+ else:
116
+ failed_deps.append(dep)
117
+ logger.error(f"Failed to install dependency: {dep}")
118
+ except Exception as e:
119
+ failed_deps.append(dep)
120
+ logger.error(f"Error installing dependency {dep}: {e}")
121
+
122
+ success = len(failed_deps) == 0
123
+
124
+ # Reload installed packages cache
125
+ if success:
126
+ self._load_installed_packages()
127
+
128
+ return success, installed_deps, failed_deps
129
+
130
+ def _install_single_dependency(self, dependency: str, user_install: bool = False) -> bool:
131
+ """
132
+ Install a single dependency using pip.
133
+
134
+ Args:
135
+ dependency: Dependency name or spec
136
+ user_install: Whether to install for current user only
137
+
138
+ Returns:
139
+ True if installation successful, False otherwise
140
+ """
141
+ try:
142
+ # Build pip command
143
+ cmd = [sys.executable, "-m", "pip", "install"]
144
+
145
+ if user_install:
146
+ cmd.append("--user")
147
+
148
+ # Add quiet flag to reduce output
149
+ cmd.append("--quiet")
150
+
151
+ # Add dependency
152
+ cmd.append(dependency)
153
+
154
+ logger.debug(f"Installing dependency: {' '.join(cmd)}")
155
+
156
+ # Run pip install
157
+ result = subprocess.run(
158
+ cmd,
159
+ capture_output=True,
160
+ text=True,
161
+ timeout=300 # 5 minutes timeout
162
+ )
163
+
164
+ if result.returncode == 0:
165
+ logger.debug(f"Successfully installed {dependency}")
166
+ return True
167
+ else:
168
+ logger.error(f"Failed to install {dependency}: {result.stderr}")
169
+ return False
170
+
171
+ except subprocess.TimeoutExpired:
172
+ logger.error(f"Timeout while installing {dependency}")
173
+ return False
174
+ except Exception as e:
175
+ logger.error(f"Error installing {dependency}: {e}")
176
+ return False
177
+
178
+ def verify_installation(self, dependencies: List[str]) -> Tuple[bool, List[str]]:
179
+ """
180
+ Verify that dependencies are properly installed.
181
+
182
+ Args:
183
+ dependencies: List of dependencies to verify
184
+
185
+ Returns:
186
+ Tuple of (all_verified, failed_verifications)
187
+ """
188
+ if not dependencies:
189
+ return True, []
190
+
191
+ failed_verifications = []
192
+
193
+ for dep in dependencies:
194
+ if not self._is_dependency_satisfied(dep):
195
+ failed_verifications.append(dep)
196
+
197
+ all_verified = len(failed_verifications) == 0
198
+ return all_verified, failed_verifications
199
+
200
+ def get_dependency_info(self, dependency: str) -> Dict[str, Any]:
201
+ """
202
+ Get information about a dependency.
203
+
204
+ Args:
205
+ dependency: Dependency name
206
+
207
+ Returns:
208
+ Dictionary with dependency information
209
+ """
210
+ info = {
211
+ "name": dependency,
212
+ "installed": False,
213
+ "version": None,
214
+ "importable": False
215
+ }
216
+
217
+ # Check if it's installed
218
+ try:
219
+ dist = pkg_resources.get_distribution(dependency)
220
+ info["installed"] = True
221
+ info["version"] = dist.version
222
+ except pkg_resources.DistributionNotFound:
223
+ pass
224
+
225
+ # Check if it's importable
226
+ try:
227
+ importlib.import_module(dependency)
228
+ info["importable"] = True
229
+ except ImportError:
230
+ pass
231
+
232
+ return info
233
+
234
+ def list_installed_dependencies(self) -> Dict[str, str]:
235
+ """
236
+ Get list of all installed packages.
237
+
238
+ Returns:
239
+ Dictionary mapping package names to versions
240
+ """
241
+ return self._installed_packages.copy()
242
+
243
+
244
+ # Global instance
245
+ dependency_manager = DependencyManager()
@@ -12,6 +12,7 @@ from typing import Dict, Any, Optional
12
12
  from mcp_proxy_adapter.commands.base import Command
13
13
  from mcp_proxy_adapter.commands.result import CommandResult, SuccessResult
14
14
  from mcp_proxy_adapter.commands.command_registry import registry
15
+ from mcp_proxy_adapter.core.proxy_registration import get_proxy_registration_status
15
16
 
16
17
 
17
18
  class HealthResult(SuccessResult):
@@ -117,6 +118,12 @@ class HealthCommand(Command):
117
118
  },
118
119
  "commands": {
119
120
  "registered_count": len(registry.get_all_commands())
121
+ },
122
+ "proxy_registration": {
123
+ "enabled": get_proxy_registration_status().get("enabled", False),
124
+ "registered": get_proxy_registration_status().get("registered", False),
125
+ "server_key": get_proxy_registration_status().get("server_key"),
126
+ "proxy_url": get_proxy_registration_status().get("proxy_url")
120
127
  }
121
128
  }
122
129
  )