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,331 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Author: Vasiliy Zdanovskiy
4
+ email: vasilyvz@gmail.com
5
+ Script for generating test configurations for MCP Proxy Adapter.
6
+ Generates 6 different configuration types for testing various security scenarios.
7
+ """
8
+ import json
9
+ import os
10
+ import argparse
11
+ from typing import Dict, Any
12
+ def generate_http_simple_config(port: int = 20000, certs_dir: str = "certs", keys_dir: str = "keys") -> Dict[str, Any]:
13
+ """Generate HTTP configuration without authorization."""
14
+ return {
15
+ "server": {"host": "127.0.0.1", "port": port},
16
+ "ssl": {"enabled": False},
17
+ "security": {"enabled": False},
18
+ "registration": {
19
+ "enabled": False,
20
+ "auth_method": "token",
21
+ "server_url": "http://127.0.0.1:3004/proxy",
22
+ "token": {"enabled": True, "token": "proxy_registration_token_123"},
23
+ "proxy_info": {
24
+ "name": "mcp_example_server",
25
+ "capabilities": ["jsonrpc", "rest", "proxy_registration"],
26
+ "endpoints": {"jsonrpc": "/api/jsonrpc", "rest": "/cmd", "health": "/health"}
27
+ },
28
+ "heartbeat": {"enabled": True, "interval": 30}
29
+ },
30
+ "protocols": {"enabled": True, "allowed_protocols": ["http"]}
31
+ }
32
+ def generate_http_token_config(port: int = 20001, certs_dir: str = "certs", keys_dir: str = "keys", roles_file: str = "configs/roles.json") -> Dict[str, Any]:
33
+ """Generate HTTP configuration with token authorization."""
34
+ return {
35
+ "server": {"host": "127.0.0.1", "port": port},
36
+ "ssl": {"enabled": False},
37
+ "security": {
38
+ "enabled": True,
39
+ "auth": {
40
+ "enabled": True,
41
+ "methods": ["api_key"],
42
+ # Map API tokens to roles for testing
43
+ "api_keys": {
44
+ "test-token-123": "admin",
45
+ "user-token-456": "user",
46
+ "readonly-token-123": "readonly",
47
+ "guest-token-123": "guest",
48
+ "proxy-token-123": "proxy"
49
+ }
50
+ },
51
+ "permissions": {"enabled": True, "roles_file": roles_file}
52
+ },
53
+ "registration": {
54
+ "enabled": True,
55
+ "url": "http://127.0.0.1:3004/proxy",
56
+ "name": "http_token_adapter",
57
+ "capabilities": ["http", "token_auth"],
58
+ "retry_count": 3,
59
+ "retry_delay": 5,
60
+ "heartbeat": {"enabled": True, "interval": 30}
61
+ },
62
+ "protocols": {"enabled": True, "allowed_protocols": ["http"]}
63
+ }
64
+ def generate_https_simple_config(port: int = 20002, certs_dir: str = "certs", keys_dir: str = "keys") -> Dict[str, Any]:
65
+ """Generate HTTPS configuration without client certificate verification and authorization."""
66
+ return {
67
+ "server": {"host": "127.0.0.1", "port": port},
68
+ "ssl": {
69
+ "enabled": True,
70
+ "cert_file": f"{certs_dir}/localhost_server.crt",
71
+ "key_file": f"{keys_dir}/localhost_server.key"
72
+ },
73
+ "security": {"enabled": False},
74
+ "registration": {
75
+ "enabled": True,
76
+ "url": "http://127.0.0.1:3004/proxy",
77
+ "name": "https_simple_adapter",
78
+ "capabilities": ["https"],
79
+ "retry_count": 3,
80
+ "retry_delay": 5,
81
+ "heartbeat": {"enabled": True, "interval": 30}
82
+ },
83
+ "protocols": {"enabled": True, "allowed_protocols": ["http", "https"]}
84
+ }
85
+ def generate_https_token_config(port: int = 20003, certs_dir: str = "certs", keys_dir: str = "keys") -> Dict[str, Any]:
86
+ """Generate HTTPS configuration without client certificate verification with token authorization."""
87
+ return {
88
+ "server": {"host": "127.0.0.1", "port": port},
89
+ "ssl": {
90
+ "enabled": True,
91
+ "cert_file": f"{certs_dir}/localhost_server.crt",
92
+ "key_file": f"{keys_dir}/localhost_server.key"
93
+ },
94
+ "security": {
95
+ "enabled": True,
96
+ "auth": {
97
+ "enabled": True,
98
+ "methods": ["api_key"],
99
+ "api_keys": {
100
+ "test-token-123": "admin",
101
+ "user-token-456": "user",
102
+ "readonly-token-123": "readonly",
103
+ "guest-token-123": "guest",
104
+ "proxy-token-123": "proxy"
105
+ }
106
+ },
107
+ "permissions": {"enabled": True, "roles_file": "./configs/roles.json"}
108
+ },
109
+ "registration": {
110
+ "enabled": True,
111
+ "url": "http://127.0.0.1:3004/proxy",
112
+ "name": "https_token_adapter",
113
+ "capabilities": ["https", "token_auth"],
114
+ "retry_count": 3,
115
+ "retry_delay": 5,
116
+ "heartbeat": {"enabled": True, "interval": 30}
117
+ },
118
+ "protocols": {"enabled": True, "allowed_protocols": ["http", "https"]}
119
+ }
120
+ def generate_mtls_no_roles_config(port: int = 20004, certs_dir: str = "certs", keys_dir: str = "keys") -> Dict[str, Any]:
121
+ """Generate mTLS configuration without roles."""
122
+ return {
123
+ "server": {"host": "127.0.0.1", "port": port},
124
+ "ssl": {
125
+ "enabled": True,
126
+ "cert_file": f"{certs_dir}/localhost_server.crt",
127
+ "key_file": f"{keys_dir}/localhost_server.key",
128
+ "ca_cert": f"{certs_dir}/mcp_proxy_adapter_ca_ca.crt",
129
+ "verify_client": True
130
+ },
131
+ "security": {
132
+ "enabled": True,
133
+ "auth": {"enabled": True, "methods": ["certificate"]},
134
+ "permissions": {"enabled": False}
135
+ },
136
+ "protocols": {"enabled": True, "allowed_protocols": ["https", "mtls"]}
137
+ }
138
+ def generate_mtls_with_roles_config(port: int = 20005, certs_dir: str = "certs", keys_dir: str = "keys", roles_file: str = "configs/roles.json") -> Dict[str, Any]:
139
+ """Generate mTLS configuration with roles."""
140
+ return {
141
+ "server": {"host": "127.0.0.1", "port": port},
142
+ "ssl": {
143
+ "enabled": True,
144
+ "cert_file": f"{certs_dir}/localhost_server.crt",
145
+ "key_file": f"{keys_dir}/localhost_server.key",
146
+ "ca_cert": f"{certs_dir}/mcp_proxy_adapter_ca_ca.crt",
147
+ "verify_client": True
148
+ },
149
+ "registration": {
150
+ "enabled": True,
151
+ "auth_method": "token",
152
+ "server_url": "http://127.0.0.1:3004/proxy",
153
+ "token": {"enabled": True, "token": "proxy_registration_token_123"},
154
+ "proxy_info": {
155
+ "name": "mcp_example_server",
156
+ "capabilities": ["jsonrpc", "rest", "security", "proxy_registration"],
157
+ "endpoints": {"jsonrpc": "/api/jsonrpc", "rest": "/cmd", "health": "/health"}
158
+ },
159
+ "heartbeat": {"enabled": True, "interval": 30}
160
+ },
161
+ "security": {
162
+ "enabled": True,
163
+ "auth": {"enabled": True, "methods": ["certificate"]},
164
+ "permissions": {"enabled": True, "roles_file": roles_file}
165
+ },
166
+ "protocols": {"enabled": True, "allowed_protocols": ["https", "mtls"]}
167
+ }
168
+ def generate_roles_config() -> Dict[str, Any]:
169
+ """Generate roles configuration for testing."""
170
+ return {
171
+ "admin": {
172
+ "description": "Administrator role with full access",
173
+ "permissions": [
174
+ "read",
175
+ "write",
176
+ "execute",
177
+ "delete",
178
+ "admin",
179
+ "register",
180
+ "unregister",
181
+ "heartbeat",
182
+ "discover"
183
+ ],
184
+ "tokens": ["test-token-123"]
185
+ },
186
+ "user": {
187
+ "description": "User role with limited access",
188
+ "permissions": [
189
+ "read",
190
+ "execute",
191
+ "register",
192
+ "unregister",
193
+ "heartbeat",
194
+ "discover"
195
+ ],
196
+ "tokens": ["user-token-456"]
197
+ },
198
+ "readonly": {
199
+ "description": "Read-only role",
200
+ "permissions": [
201
+ "read",
202
+ "discover"
203
+ ],
204
+ "tokens": ["readonly-token-123"]
205
+ },
206
+ "guest": {
207
+ "description": "Guest role with read-only access",
208
+ "permissions": [
209
+ "read",
210
+ "discover"
211
+ ],
212
+ "tokens": ["guest-token-123"]
213
+ },
214
+ "proxy": {
215
+ "description": "Proxy role for registration",
216
+ "permissions": [
217
+ "register",
218
+ "unregister",
219
+ "heartbeat",
220
+ "discover"
221
+ ],
222
+ "tokens": ["proxy-token-123"]
223
+ }
224
+ }
225
+ def generate_all_configs(output_dir: str, certs_dir: str = "certs", keys_dir: str = "keys", roles_file: str = "configs/roles.json") -> None:
226
+ """Generate all 6 configuration types and save them to files."""
227
+ # Ensure output directory exists first
228
+ os.makedirs(output_dir, exist_ok=True)
229
+
230
+ configs = {
231
+ "http_simple": generate_http_simple_config(20000, certs_dir, keys_dir),
232
+ "http_token": generate_http_token_config(20001, certs_dir, keys_dir, roles_file),
233
+ "https_simple": generate_https_simple_config(20002, certs_dir, keys_dir),
234
+ "https_token": generate_https_token_config(20003, certs_dir, keys_dir),
235
+ "mtls_no_roles": generate_mtls_no_roles_config(20004, certs_dir, keys_dir),
236
+ "mtls_with_roles": generate_mtls_with_roles_config(20005, certs_dir, keys_dir, roles_file)
237
+ }
238
+ # Ensure output directory exists
239
+ os.makedirs(output_dir, exist_ok=True)
240
+ # Generate each configuration
241
+ for name, config in configs.items():
242
+ filename = os.path.join(output_dir, f"{name}.json")
243
+ with open(filename, 'w', encoding='utf-8') as f:
244
+ json.dump(config, f, indent=2, ensure_ascii=False)
245
+ print(f"Generated: {filename}")
246
+ # Generate roles configuration
247
+ roles_config = generate_roles_config()
248
+
249
+ # Create roles.json in the root directory (test environment root) for compatibility
250
+ # When running as module, we need to create roles.json in the current working directory
251
+ # This is the directory where the user is running the command from
252
+ try:
253
+ # Get the current working directory where the user is running the command
254
+ current_dir = os.getcwd()
255
+ root_roles_filename = os.path.join(current_dir, "roles.json")
256
+
257
+ # Create roles.json in the current working directory
258
+ with open(root_roles_filename, 'w', encoding='utf-8') as f:
259
+ json.dump(roles_config, f, indent=2, ensure_ascii=False)
260
+ print(f"Generated: {root_roles_filename}")
261
+
262
+ # Also create a copy in the output directory for reference
263
+ backup_roles_filename = os.path.join(output_dir, "roles_backup.json")
264
+ with open(backup_roles_filename, 'w', encoding='utf-8') as f:
265
+ json.dump(roles_config, f, indent=2, ensure_ascii=False)
266
+ print(f"Generated backup: {backup_roles_filename}")
267
+
268
+ except Exception as e:
269
+ print(f"Warning: Could not create roles.json in current directory: {e}")
270
+ print(f"Current working directory: {os.getcwd()}")
271
+ print(f"Script directory: {os.path.dirname(os.path.abspath(__file__))}")
272
+
273
+ # Also create roles.json in configs directory for reference
274
+ roles_filename = os.path.join(output_dir, "roles.json")
275
+ with open(roles_filename, 'w', encoding='utf-8') as f:
276
+ json.dump(roles_config, f, indent=2, ensure_ascii=False)
277
+ print(f"Generated: {roles_filename}")
278
+ print(f"\nGenerated {len(configs)} configuration files and roles.json in {output_dir}")
279
+
280
+ print("\n" + "=" * 60)
281
+ print("āœ… CONFIGURATION GENERATION COMPLETED SUCCESSFULLY")
282
+ print("=" * 60)
283
+ print("\nšŸ“‹ NEXT STEPS:")
284
+ print("1. Run security tests:")
285
+ print(" python -m mcp_proxy_adapter.examples.run_security_tests")
286
+ print("\n2. Start basic framework example:")
287
+ print(" python -m mcp_proxy_adapter.examples.basic_framework.main --config configs/https_simple.json")
288
+ print("\n3. Start full application example:")
289
+ print(" python -m mcp_proxy_adapter.examples.full_application.main --config configs/mtls_with_roles.json")
290
+ print("=" * 60)
291
+ def main():
292
+ """Main function for command line execution."""
293
+ parser = argparse.ArgumentParser(
294
+ description="Generate test configurations for MCP Proxy Adapter"
295
+ )
296
+ parser.add_argument(
297
+ "--output-dir",
298
+ default="configs",
299
+ help="Output directory for configuration files (default: configs)"
300
+ )
301
+ parser.add_argument(
302
+ "--certs-dir",
303
+ default="certs",
304
+ help="Certificates directory (default: certs)"
305
+ )
306
+ parser.add_argument(
307
+ "--keys-dir",
308
+ default="keys",
309
+ help="Keys directory (default: keys)"
310
+ )
311
+ parser.add_argument(
312
+ "--roles-file",
313
+ default="configs/roles.json",
314
+ help="Roles file path (default: configs/roles.json)"
315
+ )
316
+ args = parser.parse_args()
317
+ try:
318
+ generate_all_configs(args.output_dir, args.certs_dir, args.keys_dir, args.roles_file)
319
+ print("Configuration generation completed successfully!")
320
+ except Exception as e:
321
+ print(f"\nāŒ CONFIGURATION GENERATION FAILED: {e}")
322
+ print("=" * 60)
323
+ print("\nšŸ”§ TROUBLESHOOTING:")
324
+ print("1. Check if output directory is writable")
325
+ print("2. Verify JSON encoding support")
326
+ print("3. Check available disk space")
327
+ print("=" * 60)
328
+ return 1
329
+ return 0
330
+ if __name__ == "__main__":
331
+ exit(main())
@@ -0,0 +1,334 @@
1
+ """
2
+ Proxy Registration Example
3
+ This example demonstrates how to use the MCP Proxy Adapter framework
4
+ for proxy registration with different authentication methods.
5
+ Author: Vasiliy Zdanovskiy
6
+ email: vasilyvz@gmail.com
7
+ """
8
+ import asyncio
9
+ import json
10
+ import sys
11
+ import os
12
+ from pathlib import Path
13
+ from typing import Dict, Any, Optional
14
+ # Add project root to path
15
+ project_root = Path(__file__).parent.parent.parent
16
+ sys.path.insert(0, str(project_root))
17
+ import aiohttp
18
+ from aiohttp import ClientTimeout, TCPConnector
19
+ import ssl
20
+ from mcp_proxy_adapter.core.logging import logger
21
+ class ProxyRegistrationExample:
22
+ """Example client for testing proxy registration functionality."""
23
+ def __init__(self, server_url: str, auth_token: Optional[str] = None):
24
+ """
25
+ Initialize example client.
26
+ Args:
27
+ server_url: Server URL
28
+ auth_token: Authentication token
29
+ """
30
+ self.server_url = server_url
31
+ self.auth_token = auth_token
32
+ self.session: Optional[aiohttp.ClientSession] = None
33
+ # Test data
34
+ self.test_servers = [
35
+ {
36
+ "server_id": "example-server-1",
37
+ "server_url": "http://localhost:8001",
38
+ "server_name": "Example Server 1",
39
+ "description": "Example server for registration testing",
40
+ "version": "1.0.0",
41
+ "capabilities": ["jsonrpc", "rest"],
42
+ "endpoints": {
43
+ "jsonrpc": "/api/jsonrpc",
44
+ "rest": "/cmd",
45
+ "health": "/health"
46
+ },
47
+ "auth_method": "api_key",
48
+ "security_enabled": True
49
+ },
50
+ {
51
+ "server_id": "example-server-2",
52
+ "server_url": "http://localhost:8002",
53
+ "server_name": "Example Server 2",
54
+ "description": "Another example server",
55
+ "version": "1.0.0",
56
+ "capabilities": ["jsonrpc", "rest", "security"],
57
+ "endpoints": {
58
+ "jsonrpc": "/api/jsonrpc",
59
+ "rest": "/cmd",
60
+ "health": "/health"
61
+ },
62
+ "auth_method": "certificate",
63
+ "security_enabled": True
64
+ }
65
+ ]
66
+ async def __aenter__(self):
67
+ """Async context manager entry."""
68
+ # Create SSL context for HTTPS
69
+ ssl_context = None
70
+ if self.server_url.startswith("https"):
71
+ ssl_context = ssl.create_default_context()
72
+ ssl_context.check_hostname = False
73
+ ssl_context.verify_mode = ssl.CERT_NONE
74
+ # Create connector
75
+ connector = TCPConnector(ssl=ssl_context) if ssl_context else None
76
+ # Create session
77
+ timeout = ClientTimeout(total=30)
78
+ self.session = aiohttp.ClientSession(
79
+ connector=connector,
80
+ timeout=timeout
81
+ )
82
+ return self
83
+ async def __aexit__(self, exc_type, exc_val, exc_tb):
84
+ """Async context manager exit."""
85
+ if self.session:
86
+ await self.session.close()
87
+ def _get_headers(self) -> Dict[str, str]:
88
+ """Get request headers with authentication."""
89
+ headers = {
90
+ "Content-Type": "application/json"
91
+ }
92
+ if self.auth_token:
93
+ headers["X-API-Key"] = self.auth_token
94
+ return headers
95
+ async def test_registration(self, server_data: Dict[str, Any]) -> Dict[str, Any]:
96
+ """
97
+ Test registration with authentication.
98
+ Args:
99
+ server_data: Server registration data
100
+ Returns:
101
+ Test result
102
+ """
103
+ try:
104
+ # Prepare JSON-RPC request
105
+ request_data = {
106
+ "jsonrpc": "2.0",
107
+ "id": 1,
108
+ "method": "proxy_registration",
109
+ "params": {
110
+ "operation": "register",
111
+ **server_data
112
+ }
113
+ }
114
+ logger.info(f"Testing registration for server: {server_data['server_id']}")
115
+ logger.debug(f"Request data: {json.dumps(request_data, indent=2)}")
116
+ # Make request
117
+ async with self.session.post(
118
+ f"{self.server_url}/cmd",
119
+ json=request_data,
120
+ headers=self._get_headers()
121
+ ) as response:
122
+ result = await response.json()
123
+ logger.info(f"Response status: {response.status}")
124
+ logger.debug(f"Response: {json.dumps(result, indent=2)}")
125
+ return {
126
+ "success": response.status == 200,
127
+ "status_code": response.status,
128
+ "result": result,
129
+ "server_id": server_data["server_id"]
130
+ }
131
+ except Exception as e:
132
+ logger.error(f"Registration test failed: {e}")
133
+ return {
134
+ "success": False,
135
+ "error": str(e),
136
+ "server_id": server_data["server_id"]
137
+ }
138
+ async def test_discovery(self) -> Dict[str, Any]:
139
+ """
140
+ Test discovery operation.
141
+ Returns:
142
+ Test result
143
+ """
144
+ try:
145
+ # Prepare JSON-RPC request
146
+ request_data = {
147
+ "jsonrpc": "2.0",
148
+ "id": 1,
149
+ "method": "proxy_registration",
150
+ "params": {
151
+ "operation": "discover"
152
+ }
153
+ }
154
+ logger.info("Testing discovery operation")
155
+ # Make request
156
+ async with self.session.post(
157
+ f"{self.server_url}/cmd",
158
+ json=request_data,
159
+ headers=self._get_headers()
160
+ ) as response:
161
+ result = await response.json()
162
+ logger.info(f"Response status: {response.status}")
163
+ logger.debug(f"Response: {json.dumps(result, indent=2)}")
164
+ return {
165
+ "success": response.status == 200,
166
+ "status_code": response.status,
167
+ "result": result
168
+ }
169
+ except Exception as e:
170
+ logger.error(f"Discovery test failed: {e}")
171
+ return {
172
+ "success": False,
173
+ "error": str(e)
174
+ }
175
+ async def test_heartbeat(self, server_key: str) -> Dict[str, Any]:
176
+ """
177
+ Test heartbeat operation.
178
+ Args:
179
+ server_key: Server key for heartbeat
180
+ Returns:
181
+ Test result
182
+ """
183
+ try:
184
+ # Prepare JSON-RPC request
185
+ request_data = {
186
+ "jsonrpc": "2.0",
187
+ "id": 1,
188
+ "method": "proxy_registration",
189
+ "params": {
190
+ "operation": "heartbeat",
191
+ "server_key": server_key,
192
+ "timestamp": 1234567890,
193
+ "status": "healthy"
194
+ }
195
+ }
196
+ logger.info(f"Testing heartbeat for server: {server_key}")
197
+ # Make request
198
+ async with self.session.post(
199
+ f"{self.server_url}/cmd",
200
+ json=request_data,
201
+ headers=self._get_headers()
202
+ ) as response:
203
+ result = await response.json()
204
+ logger.info(f"Response status: {response.status}")
205
+ logger.debug(f"Response: {json.dumps(result, indent=2)}")
206
+ return {
207
+ "success": response.status == 200,
208
+ "status_code": response.status,
209
+ "result": result,
210
+ "server_key": server_key
211
+ }
212
+ except Exception as e:
213
+ logger.error(f"Heartbeat test failed: {e}")
214
+ return {
215
+ "success": False,
216
+ "error": str(e),
217
+ "server_key": server_key
218
+ }
219
+ async def run_proxy_registration_example():
220
+ """Run proxy registration example."""
221
+ logger.info("šŸš€ Starting proxy registration example")
222
+ # Test configurations
223
+ test_configs = [
224
+ {
225
+ "name": "Admin Token",
226
+ "server_url": "http://localhost:8002",
227
+ "auth_token": "test-token-123"
228
+ },
229
+ {
230
+ "name": "User Token",
231
+ "server_url": "http://localhost:8002",
232
+ "auth_token": "user-token-456"
233
+ },
234
+ {
235
+ "name": "Readonly Token",
236
+ "server_url": "http://localhost:8002",
237
+ "auth_token": "readonly-token-123"
238
+ }
239
+ ]
240
+ results = []
241
+ for config in test_configs:
242
+ logger.info(f"\nšŸ“‹ Testing: {config['name']}")
243
+ logger.info(f"Server URL: {config['server_url']}")
244
+ logger.info(f"Auth Token: {config['auth_token']}")
245
+ async with ProxyRegistrationExample(
246
+ config['server_url'],
247
+ config['auth_token']
248
+ ) as client:
249
+ # Test registration
250
+ for server_data in client.test_servers:
251
+ result = await client.test_registration(server_data)
252
+ results.append({
253
+ "test": f"{config['name']} - Registration",
254
+ "server_id": server_data["server_id"],
255
+ **result
256
+ })
257
+ # If registration successful, test heartbeat
258
+ if result["success"] and "result" in result:
259
+ server_key = result["result"].get("result", {}).get("server_key")
260
+ if server_key:
261
+ heartbeat_result = await client.test_heartbeat(server_key)
262
+ results.append({
263
+ "test": f"{config['name']} - Heartbeat",
264
+ "server_key": server_key,
265
+ **heartbeat_result
266
+ })
267
+ # Test discovery
268
+ discovery_result = await client.test_discovery()
269
+ results.append({
270
+ "test": f"{config['name']} - Discovery",
271
+ **discovery_result
272
+ })
273
+ # Test without authentication
274
+ logger.info(f"\nšŸ“‹ Testing: No Authentication")
275
+ async with ProxyRegistrationExample("http://localhost:8002") as client:
276
+ for server_data in client.test_servers:
277
+ result = await client.test_registration(server_data)
278
+ results.append({
279
+ "test": "No Auth - Registration",
280
+ "server_id": server_data["server_id"],
281
+ **result
282
+ })
283
+ # Print results
284
+ logger.info("\n" + "="*80)
285
+ logger.info("šŸ“Š EXAMPLE RESULTS")
286
+ logger.info("="*80)
287
+ passed = 0
288
+ failed = 0
289
+ for result in results:
290
+ status = "āœ… PASS" if result["success"] else "āŒ FAIL"
291
+ logger.info(f"{status} {result['test']}")
292
+ if result["success"]:
293
+ passed += 1
294
+ else:
295
+ failed += 1
296
+ if "error" in result:
297
+ logger.error(f" Error: {result['error']}")
298
+ elif "result" in result:
299
+ result_data = result["result"]
300
+ if "error" in result_data:
301
+ logger.error(f" API Error: {result_data['error']}")
302
+ elif "result" in result_data:
303
+ api_result = result_data["result"]
304
+ if "server_key" in api_result:
305
+ logger.info(f" Server Key: {api_result['server_key']}")
306
+ if "message" in api_result:
307
+ logger.info(f" Message: {api_result['message']}")
308
+ logger.info("\n" + "="*80)
309
+ logger.info(f"šŸ“ˆ SUMMARY: {passed} passed, {failed} failed")
310
+ logger.info("="*80)
311
+ return passed, failed
312
+ def main():
313
+ """Main function for the example."""
314
+ logger.info("šŸ”§ MCP Proxy Adapter - Proxy Registration Example")
315
+ logger.info("="*60)
316
+ # Check if server is running
317
+ import socket
318
+ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
319
+ result = sock.connect_ex(('localhost', 8002))
320
+ sock.close()
321
+ if result != 0:
322
+ logger.error("āŒ Server is not running on localhost:8002")
323
+ logger.info("šŸ’” Please start the server first:")
324
+ logger.info(" cd mcp_proxy_adapter/examples")
325
+ logger.info(" python -m mcp_proxy_adapter.main --config server_configs/config_proxy_registration.json")
326
+ sys.exit(1)
327
+ logger.info("āœ… Server is running on localhost:8002")
328
+ logger.info("šŸš€ Starting proxy registration example...")
329
+ # Run example
330
+ passed, failed = asyncio.run(run_proxy_registration_example())
331
+ # Exit with appropriate code
332
+ sys.exit(0 if failed == 0 else 1)
333
+ if __name__ == "__main__":
334
+ main()