mcp-proxy-adapter 6.3.4__py3-none-any.whl → 6.3.6__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 (131) hide show
  1. mcp_proxy_adapter/__init__.py +9 -5
  2. mcp_proxy_adapter/__main__.py +1 -1
  3. mcp_proxy_adapter/api/app.py +227 -176
  4. mcp_proxy_adapter/api/handlers.py +68 -60
  5. mcp_proxy_adapter/api/middleware/__init__.py +7 -5
  6. mcp_proxy_adapter/api/middleware/base.py +19 -16
  7. mcp_proxy_adapter/api/middleware/command_permission_middleware.py +44 -34
  8. mcp_proxy_adapter/api/middleware/error_handling.py +57 -67
  9. mcp_proxy_adapter/api/middleware/factory.py +50 -52
  10. mcp_proxy_adapter/api/middleware/logging.py +46 -30
  11. mcp_proxy_adapter/api/middleware/performance.py +19 -16
  12. mcp_proxy_adapter/api/middleware/protocol_middleware.py +80 -50
  13. mcp_proxy_adapter/api/middleware/transport_middleware.py +26 -24
  14. mcp_proxy_adapter/api/middleware/unified_security.py +70 -51
  15. mcp_proxy_adapter/api/middleware/user_info_middleware.py +43 -34
  16. mcp_proxy_adapter/api/schemas.py +69 -43
  17. mcp_proxy_adapter/api/tool_integration.py +83 -63
  18. mcp_proxy_adapter/api/tools.py +60 -50
  19. mcp_proxy_adapter/commands/__init__.py +15 -6
  20. mcp_proxy_adapter/commands/auth_validation_command.py +107 -110
  21. mcp_proxy_adapter/commands/base.py +108 -112
  22. mcp_proxy_adapter/commands/builtin_commands.py +28 -18
  23. mcp_proxy_adapter/commands/catalog_manager.py +394 -265
  24. mcp_proxy_adapter/commands/cert_monitor_command.py +222 -204
  25. mcp_proxy_adapter/commands/certificate_management_command.py +210 -213
  26. mcp_proxy_adapter/commands/command_registry.py +275 -226
  27. mcp_proxy_adapter/commands/config_command.py +48 -33
  28. mcp_proxy_adapter/commands/dependency_container.py +22 -23
  29. mcp_proxy_adapter/commands/dependency_manager.py +65 -56
  30. mcp_proxy_adapter/commands/echo_command.py +15 -15
  31. mcp_proxy_adapter/commands/health_command.py +31 -29
  32. mcp_proxy_adapter/commands/help_command.py +97 -61
  33. mcp_proxy_adapter/commands/hooks.py +65 -49
  34. mcp_proxy_adapter/commands/key_management_command.py +148 -147
  35. mcp_proxy_adapter/commands/load_command.py +58 -40
  36. mcp_proxy_adapter/commands/plugins_command.py +80 -54
  37. mcp_proxy_adapter/commands/protocol_management_command.py +60 -48
  38. mcp_proxy_adapter/commands/proxy_registration_command.py +107 -115
  39. mcp_proxy_adapter/commands/reload_command.py +43 -37
  40. mcp_proxy_adapter/commands/result.py +26 -33
  41. mcp_proxy_adapter/commands/role_test_command.py +26 -26
  42. mcp_proxy_adapter/commands/roles_management_command.py +176 -173
  43. mcp_proxy_adapter/commands/security_command.py +134 -122
  44. mcp_proxy_adapter/commands/settings_command.py +47 -56
  45. mcp_proxy_adapter/commands/ssl_setup_command.py +109 -129
  46. mcp_proxy_adapter/commands/token_management_command.py +129 -158
  47. mcp_proxy_adapter/commands/transport_management_command.py +41 -36
  48. mcp_proxy_adapter/commands/unload_command.py +42 -37
  49. mcp_proxy_adapter/config.py +36 -35
  50. mcp_proxy_adapter/core/__init__.py +19 -21
  51. mcp_proxy_adapter/core/app_factory.py +30 -9
  52. mcp_proxy_adapter/core/app_runner.py +81 -64
  53. mcp_proxy_adapter/core/auth_validator.py +176 -182
  54. mcp_proxy_adapter/core/certificate_utils.py +469 -426
  55. mcp_proxy_adapter/core/client.py +155 -126
  56. mcp_proxy_adapter/core/client_manager.py +60 -54
  57. mcp_proxy_adapter/core/client_security.py +120 -91
  58. mcp_proxy_adapter/core/config_converter.py +176 -143
  59. mcp_proxy_adapter/core/config_validator.py +12 -4
  60. mcp_proxy_adapter/core/crl_utils.py +21 -7
  61. mcp_proxy_adapter/core/errors.py +64 -20
  62. mcp_proxy_adapter/core/logging.py +34 -29
  63. mcp_proxy_adapter/core/mtls_asgi.py +29 -25
  64. mcp_proxy_adapter/core/mtls_asgi_app.py +66 -54
  65. mcp_proxy_adapter/core/protocol_manager.py +154 -104
  66. mcp_proxy_adapter/core/proxy_client.py +202 -144
  67. mcp_proxy_adapter/core/proxy_registration.py +7 -3
  68. mcp_proxy_adapter/core/role_utils.py +139 -125
  69. mcp_proxy_adapter/core/security_adapter.py +88 -77
  70. mcp_proxy_adapter/core/security_factory.py +50 -44
  71. mcp_proxy_adapter/core/security_integration.py +72 -24
  72. mcp_proxy_adapter/core/server_adapter.py +68 -64
  73. mcp_proxy_adapter/core/server_engine.py +71 -53
  74. mcp_proxy_adapter/core/settings.py +68 -58
  75. mcp_proxy_adapter/core/ssl_utils.py +69 -56
  76. mcp_proxy_adapter/core/transport_manager.py +72 -60
  77. mcp_proxy_adapter/core/unified_config_adapter.py +201 -150
  78. mcp_proxy_adapter/core/utils.py +4 -2
  79. mcp_proxy_adapter/custom_openapi.py +107 -99
  80. mcp_proxy_adapter/examples/basic_framework/main.py +9 -2
  81. mcp_proxy_adapter/examples/commands/__init__.py +1 -1
  82. mcp_proxy_adapter/examples/create_certificates_simple.py +182 -71
  83. mcp_proxy_adapter/examples/debug_request_state.py +38 -19
  84. mcp_proxy_adapter/examples/debug_role_chain.py +53 -20
  85. mcp_proxy_adapter/examples/demo_client.py +48 -36
  86. mcp_proxy_adapter/examples/examples/basic_framework/main.py +9 -2
  87. mcp_proxy_adapter/examples/examples/full_application/__init__.py +1 -0
  88. mcp_proxy_adapter/examples/examples/full_application/commands/custom_echo_command.py +22 -10
  89. mcp_proxy_adapter/examples/examples/full_application/commands/dynamic_calculator_command.py +24 -17
  90. mcp_proxy_adapter/examples/examples/full_application/hooks/application_hooks.py +16 -3
  91. mcp_proxy_adapter/examples/examples/full_application/hooks/builtin_command_hooks.py +13 -3
  92. mcp_proxy_adapter/examples/examples/full_application/main.py +27 -2
  93. mcp_proxy_adapter/examples/examples/full_application/proxy_endpoints.py +48 -14
  94. mcp_proxy_adapter/examples/full_application/__init__.py +1 -0
  95. mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +22 -10
  96. mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +24 -17
  97. mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +16 -3
  98. mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +13 -3
  99. mcp_proxy_adapter/examples/full_application/main.py +27 -2
  100. mcp_proxy_adapter/examples/full_application/proxy_endpoints.py +48 -14
  101. mcp_proxy_adapter/examples/generate_all_certificates.py +198 -73
  102. mcp_proxy_adapter/examples/generate_certificates.py +31 -16
  103. mcp_proxy_adapter/examples/generate_certificates_and_tokens.py +220 -74
  104. mcp_proxy_adapter/examples/generate_test_configs.py +68 -91
  105. mcp_proxy_adapter/examples/proxy_registration_example.py +76 -75
  106. mcp_proxy_adapter/examples/run_example.py +23 -5
  107. mcp_proxy_adapter/examples/run_full_test_suite.py +109 -71
  108. mcp_proxy_adapter/examples/run_proxy_server.py +22 -9
  109. mcp_proxy_adapter/examples/run_security_tests.py +103 -41
  110. mcp_proxy_adapter/examples/run_security_tests_fixed.py +72 -36
  111. mcp_proxy_adapter/examples/scripts/config_generator.py +288 -187
  112. mcp_proxy_adapter/examples/scripts/create_certificates_simple.py +185 -72
  113. mcp_proxy_adapter/examples/scripts/generate_certificates_and_tokens.py +220 -74
  114. mcp_proxy_adapter/examples/security_test_client.py +196 -127
  115. mcp_proxy_adapter/examples/setup_test_environment.py +17 -29
  116. mcp_proxy_adapter/examples/test_config.py +19 -4
  117. mcp_proxy_adapter/examples/test_config_generator.py +23 -7
  118. mcp_proxy_adapter/examples/test_examples.py +84 -56
  119. mcp_proxy_adapter/examples/universal_client.py +119 -62
  120. mcp_proxy_adapter/openapi.py +108 -115
  121. mcp_proxy_adapter/utils/config_generator.py +429 -274
  122. mcp_proxy_adapter/version.py +1 -2
  123. {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.6.dist-info}/METADATA +1 -1
  124. mcp_proxy_adapter-6.3.6.dist-info/RECORD +144 -0
  125. mcp_proxy_adapter-6.3.6.dist-info/top_level.txt +2 -0
  126. mcp_proxy_adapter_issue_package/demonstrate_issue.py +178 -0
  127. mcp_proxy_adapter-6.3.4.dist-info/RECORD +0 -143
  128. mcp_proxy_adapter-6.3.4.dist-info/top_level.txt +0 -1
  129. {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.6.dist-info}/WHEEL +0 -0
  130. {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.6.dist-info}/entry_points.txt +0 -0
  131. {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.6.dist-info}/licenses/LICENSE +0 -0
@@ -12,9 +12,10 @@ import time
12
12
  from pathlib import Path
13
13
  from typing import List, Dict, Optional
14
14
 
15
+
15
16
  class FullTestSuiteRunner:
16
17
  """Comprehensive test suite runner that automates the entire testing process."""
17
-
18
+
18
19
  def __init__(self):
19
20
  """Initialize the test suite runner."""
20
21
  self.working_dir = Path.cwd()
@@ -22,92 +23,109 @@ class FullTestSuiteRunner:
22
23
  self.certs_dir = self.working_dir / "certs"
23
24
  self.keys_dir = self.working_dir / "keys"
24
25
  self.roles_file = self.working_dir / "configs" / "roles.json"
25
-
26
+
26
27
  def print_step(self, step: str, description: str):
27
28
  """Print a formatted step header."""
28
29
  print(f"\n{'='*60}")
29
30
  print(f"šŸ”§ STEP {step}: {description}")
30
31
  print(f"{'='*60}")
31
-
32
+
32
33
  def print_success(self, message: str):
33
34
  """Print a success message."""
34
35
  print(f"āœ… {message}")
35
-
36
+
36
37
  def print_error(self, message: str):
37
38
  """Print an error message."""
38
39
  print(f"āŒ {message}")
39
-
40
+
40
41
  def print_info(self, message: str):
41
42
  """Print an info message."""
42
43
  print(f"ā„¹ļø {message}")
43
-
44
+
44
45
  def check_environment(self) -> bool:
45
46
  """Check if the environment is properly set up."""
46
47
  self.print_step("1", "Environment Validation")
47
-
48
+
48
49
  # Check if we're in a virtual environment
49
- if not hasattr(sys, 'real_prefix') and not (hasattr(sys, 'base_prefix') and sys.base_prefix != sys.prefix):
50
+ if not hasattr(sys, "real_prefix") and not (
51
+ hasattr(sys, "base_prefix") and sys.base_prefix != sys.prefix
52
+ ):
50
53
  self.print_error("Not running in a virtual environment!")
51
54
  self.print_info("Please activate your virtual environment first:")
52
55
  self.print_info(" source venv/bin/activate # or .venv/bin/activate")
53
56
  return False
54
-
57
+
55
58
  self.print_success("Virtual environment is active")
56
-
59
+
57
60
  # Check if mcp_proxy_adapter is installed
58
61
  try:
59
62
  import mcp_proxy_adapter
60
- self.print_success(f"mcp_proxy_adapter is installed (version: {mcp_proxy_adapter.__version__})")
63
+
64
+ self.print_success(
65
+ f"mcp_proxy_adapter is installed (version: {mcp_proxy_adapter.__version__})"
66
+ )
61
67
  except ImportError:
62
68
  self.print_error("mcp_proxy_adapter is not installed!")
63
69
  self.print_info("Please install it first:")
64
70
  self.print_info(" pip install mcp_proxy_adapter")
65
71
  return False
66
-
72
+
67
73
  # Check Python version
68
74
  python_version = sys.version_info
69
75
  if python_version.major >= 3 and python_version.minor >= 8:
70
- self.print_success(f"Python version: {python_version.major}.{python_version.minor}.{python_version.micro}")
76
+ self.print_success(
77
+ f"Python version: {python_version.major}.{python_version.minor}.{python_version.micro}"
78
+ )
71
79
  else:
72
- self.print_error(f"Python {python_version.major}.{python_version.minor} is not supported. Need Python 3.8+")
80
+ self.print_error(
81
+ f"Python {python_version.major}.{python_version.minor} is not supported. Need Python 3.8+"
82
+ )
73
83
  return False
74
-
84
+
75
85
  return True
76
-
86
+
77
87
  def create_directories(self) -> bool:
78
88
  """Create necessary directories for testing."""
79
89
  self.print_step("2", "Directory Creation")
80
-
90
+
81
91
  try:
82
92
  # Create configs directory
83
93
  self.configs_dir.mkdir(exist_ok=True)
84
- self.print_success(f"Created/verified configs directory: {self.configs_dir}")
85
-
94
+ self.print_success(
95
+ f"Created/verified configs directory: {self.configs_dir}"
96
+ )
97
+
86
98
  # Create certs directory
87
99
  self.certs_dir.mkdir(exist_ok=True)
88
100
  self.print_success(f"Created/verified certs directory: {self.certs_dir}")
89
-
101
+
90
102
  # Create keys directory
91
103
  self.keys_dir.mkdir(exist_ok=True)
92
104
  self.print_success(f"Created/verified keys directory: {self.keys_dir}")
93
-
105
+
94
106
  return True
95
-
107
+
96
108
  except Exception as e:
97
109
  self.print_error(f"Failed to create directories: {e}")
98
110
  return False
99
-
111
+
100
112
  def generate_certificates(self) -> bool:
101
113
  """Generate SSL certificates for testing."""
102
114
  self.print_step("3", "Certificate Generation")
103
-
115
+
104
116
  try:
105
117
  # Run certificate generation script
106
- cmd = [sys.executable, "-m", "mcp_proxy_adapter.examples.create_certificates_simple"]
118
+ cmd = [
119
+ sys.executable,
120
+ "-m",
121
+ "mcp_proxy_adapter.examples.create_certificates_simple",
122
+ ]
107
123
  self.print_info("Running certificate generation script...")
108
-
109
- result = subprocess.run(cmd, capture_output=True, text=True, cwd=self.working_dir)
110
-
124
+
125
+ result = subprocess.run(
126
+ cmd, capture_output=True, text=True, cwd=self.working_dir
127
+ )
128
+
111
129
  if result.returncode == 0:
112
130
  self.print_success("Certificates generated successfully")
113
131
  if result.stdout:
@@ -119,22 +137,28 @@ class FullTestSuiteRunner:
119
137
  print("Error output:")
120
138
  print(result.stderr)
121
139
  return False
122
-
140
+
123
141
  except Exception as e:
124
142
  self.print_error(f"Failed to generate certificates: {e}")
125
143
  return False
126
-
144
+
127
145
  def generate_configurations(self) -> bool:
128
146
  """Generate test configurations."""
129
147
  self.print_step("4", "Configuration Generation")
130
-
148
+
131
149
  try:
132
150
  # Run configuration generation script
133
- cmd = [sys.executable, "-m", "mcp_proxy_adapter.examples.generate_test_configs"]
151
+ cmd = [
152
+ sys.executable,
153
+ "-m",
154
+ "mcp_proxy_adapter.examples.generate_test_configs",
155
+ ]
134
156
  self.print_info("Running configuration generation script...")
135
-
136
- result = subprocess.run(cmd, capture_output=True, text=True, cwd=self.working_dir)
137
-
157
+
158
+ result = subprocess.run(
159
+ cmd, capture_output=True, text=True, cwd=self.working_dir
160
+ )
161
+
138
162
  if result.returncode == 0:
139
163
  self.print_success("Configurations generated successfully")
140
164
  if result.stdout:
@@ -146,39 +170,52 @@ class FullTestSuiteRunner:
146
170
  print("Error output:")
147
171
  print(result.stderr)
148
172
  return False
149
-
173
+
150
174
  except Exception as e:
151
175
  self.print_error(f"Failed to generate configurations: {e}")
152
176
  return False
153
-
177
+
154
178
  def run_security_tests(self) -> bool:
155
179
  """Run the security test suite."""
156
180
  self.print_step("5", "Security Testing")
157
-
181
+
158
182
  try:
159
183
  # Run security tests
160
- cmd = [sys.executable, "-m", "mcp_proxy_adapter.examples.run_security_tests", "--verbose"]
184
+ cmd = [
185
+ sys.executable,
186
+ "-m",
187
+ "mcp_proxy_adapter.examples.run_security_tests",
188
+ "--verbose",
189
+ ]
161
190
  self.print_info("Running security tests...")
162
-
191
+
163
192
  # Debug: show current working directory and check files
164
193
  self.print_info(f"DEBUG: Current working directory: {os.getcwd()}")
165
194
  self.print_info(f"DEBUG: Working directory from class: {self.working_dir}")
166
-
195
+
167
196
  # Check if certificates exist before running tests
168
197
  localhost_cert = self.certs_dir / "localhost_server.crt"
169
- self.print_info(f"DEBUG: localhost_server.crt exists: {localhost_cert.exists()}")
198
+ self.print_info(
199
+ f"DEBUG: localhost_server.crt exists: {localhost_cert.exists()}"
200
+ )
170
201
  if localhost_cert.exists():
171
- self.print_info(f"DEBUG: localhost_server.crt is symlink: {localhost_cert.is_symlink()}")
202
+ self.print_info(
203
+ f"DEBUG: localhost_server.crt is symlink: {localhost_cert.is_symlink()}"
204
+ )
172
205
  if localhost_cert.is_symlink():
173
- self.print_info(f"DEBUG: localhost_server.crt symlink target: {localhost_cert.readlink()}")
174
-
206
+ self.print_info(
207
+ f"DEBUG: localhost_server.crt symlink target: {localhost_cert.readlink()}"
208
+ )
209
+
175
210
  # List all files in certs directory
176
211
  self.print_info("DEBUG: Files in certs directory:")
177
212
  for file in self.certs_dir.iterdir():
178
213
  self.print_info(f"DEBUG: {file.name} -> {file}")
179
-
180
- result = subprocess.run(cmd, capture_output=True, text=True, cwd=self.working_dir)
181
-
214
+
215
+ result = subprocess.run(
216
+ cmd, capture_output=True, text=True, cwd=self.working_dir
217
+ )
218
+
182
219
  if result.returncode == 0:
183
220
  self.print_success("Security tests completed successfully!")
184
221
  if result.stdout:
@@ -193,87 +230,85 @@ class FullTestSuiteRunner:
193
230
  print("Error output:")
194
231
  print(result.stderr)
195
232
  return False
196
-
233
+
197
234
  except Exception as e:
198
235
  self.print_error(f"Failed to run security tests: {e}")
199
236
  return False
200
-
237
+
201
238
  def cleanup(self):
202
239
  """Clean up temporary files and processes."""
203
240
  self.print_info("Cleaning up...")
204
-
241
+
205
242
  # Simple cleanup - just print success message
206
243
  # Process cleanup is handled by the test scripts themselves
207
244
  print("āœ… Cleanup completed")
208
-
209
-
210
245
 
211
246
  def cleanup_directories(self) -> bool:
212
247
  """Clean up existing test directories before starting."""
213
248
  self.print_info("Cleaning up existing test directories...")
214
-
249
+
215
250
  try:
216
251
  import shutil
217
-
252
+
218
253
  # Directories to clean
219
254
  dirs_to_clean = [self.configs_dir, self.certs_dir, self.keys_dir]
220
255
  files_to_clean = [self.working_dir / "roles.json"]
221
-
256
+
222
257
  # Remove directories
223
258
  for dir_path in dirs_to_clean:
224
259
  if dir_path.exists():
225
260
  shutil.rmtree(dir_path)
226
261
  print(f"šŸ—‘ļø Removed directory: {dir_path}")
227
-
262
+
228
263
  # Remove files
229
264
  for file_path in files_to_clean:
230
265
  if file_path.exists():
231
266
  file_path.unlink()
232
267
  print(f"šŸ—‘ļø Removed file: {file_path}")
233
-
268
+
234
269
  self.print_success("Directory cleanup completed")
235
270
  return True
236
-
271
+
237
272
  except Exception as e:
238
273
  self.print_error(f"Failed to cleanup directories: {e}")
239
274
  return False
240
-
275
+
241
276
  def run_full_suite(self) -> bool:
242
277
  """Run the complete test suite."""
243
278
  print("šŸš€ MCP Proxy Adapter - Full Test Suite")
244
279
  print("=" * 60)
245
280
  print(f"Working directory: {self.working_dir}")
246
281
  print(f"Python executable: {sys.executable}")
247
-
282
+
248
283
  try:
249
284
  # Step 0: Clean up existing directories
250
285
  if not self.cleanup_directories():
251
286
  return False
252
-
287
+
253
288
  # Step 1: Environment validation
254
289
  if not self.check_environment():
255
290
  return False
256
-
291
+
257
292
  # Step 2: Directory creation
258
293
  if not self.create_directories():
259
294
  return False
260
-
295
+
261
296
  # Step 3: Certificate generation
262
297
  if not self.generate_certificates():
263
298
  return False
264
-
299
+
265
300
  # Step 4: Configuration generation
266
301
  if not self.generate_configurations():
267
302
  return False
268
-
303
+
269
304
  # Step 5: Security testing
270
305
  if not self.run_security_tests():
271
306
  return False
272
-
307
+
273
308
  # All steps completed successfully
274
309
  print(f"\n{'='*60}")
275
310
  print("šŸŽ‰ FULL TEST SUITE COMPLETED SUCCESSFULLY!")
276
- print("="*60)
311
+ print("=" * 60)
277
312
  print("āœ… Environment validated")
278
313
  print("āœ… Directories cleaned")
279
314
  print("āœ… Directories created")
@@ -284,9 +319,9 @@ class FullTestSuiteRunner:
284
319
  print(f"šŸ“ Configurations: {self.configs_dir}")
285
320
  print(f"šŸ“ Certificates: {self.certs_dir}")
286
321
  print(f"šŸ“ Keys: {self.keys_dir}")
287
-
322
+
288
323
  return True
289
-
324
+
290
325
  except KeyboardInterrupt:
291
326
  print("\n\nāš ļø Test suite interrupted by user")
292
327
  return False
@@ -301,12 +336,14 @@ class FullTestSuiteRunner:
301
336
  except Exception as e:
302
337
  self.print_error(f"Cleanup failed in finally block: {e}")
303
338
  import traceback
339
+
304
340
  traceback.print_exc()
305
341
 
342
+
306
343
  def main():
307
344
  """Main entry point."""
308
345
  runner = FullTestSuiteRunner()
309
-
346
+
310
347
  try:
311
348
  success = runner.run_full_suite()
312
349
  sys.exit(0 if success else 1)
@@ -314,5 +351,6 @@ def main():
314
351
  print(f"āŒ Fatal error: {e}")
315
352
  sys.exit(1)
316
353
 
354
+
317
355
  if __name__ == "__main__":
318
356
  main()
@@ -52,7 +52,7 @@ class ProxyRouter:
52
52
  "metadata": registration.metadata,
53
53
  "registered_at": datetime.now().isoformat(),
54
54
  "last_heartbeat": datetime.now().isoformat(),
55
- "status": "active"
55
+ "status": "active",
56
56
  }
57
57
  print(f"āœ… Registered adapter: {adapter_id} at {registration.url}")
58
58
  return {"status": "registered", "adapter_id": adapter_id}
@@ -72,7 +72,7 @@ class ProxyRouter:
72
72
  """List all registered adapters."""
73
73
  return {
74
74
  "adapters": list(registered_adapters.values()),
75
- "count": len(registered_adapters)
75
+ "count": len(registered_adapters),
76
76
  }
77
77
 
78
78
  @self.app.get("/proxy/health")
@@ -81,14 +81,16 @@ class ProxyRouter:
81
81
  return {
82
82
  "status": "healthy",
83
83
  "timestamp": datetime.now().isoformat(),
84
- "adapters_count": len(registered_adapters)
84
+ "adapters_count": len(registered_adapters),
85
85
  }
86
86
 
87
87
  @self.app.post("/proxy/heartbeat")
88
88
  async def heartbeat(adapter_id: str):
89
89
  """Receive heartbeat from adapter."""
90
90
  if adapter_id in registered_adapters:
91
- registered_adapters[adapter_id]["last_heartbeat"] = datetime.now().isoformat()
91
+ registered_adapters[adapter_id][
92
+ "last_heartbeat"
93
+ ] = datetime.now().isoformat()
92
94
  return {"status": "ok", "adapter_id": adapter_id}
93
95
  else:
94
96
  raise HTTPException(status_code=404, detail="Adapter not found")
@@ -101,10 +103,21 @@ def create_proxy_app() -> FastAPI:
101
103
 
102
104
 
103
105
  def main() -> None:
104
- parser = argparse.ArgumentParser(description="Run local proxy server for MCP examples")
105
- parser.add_argument("--host", default="127.0.0.1", help="Host to bind to (default: 127.0.0.1)")
106
- parser.add_argument("--port", type=int, default=3004, help="Port to bind to (default: 3004)")
107
- parser.add_argument("--log-level", default="info", choices=["debug", "info", "warning", "error"], help="Log level")
106
+ parser = argparse.ArgumentParser(
107
+ description="Run local proxy server for MCP examples"
108
+ )
109
+ parser.add_argument(
110
+ "--host", default="127.0.0.1", help="Host to bind to (default: 127.0.0.1)"
111
+ )
112
+ parser.add_argument(
113
+ "--port", type=int, default=3004, help="Port to bind to (default: 3004)"
114
+ )
115
+ parser.add_argument(
116
+ "--log-level",
117
+ default="info",
118
+ choices=["debug", "info", "warning", "error"],
119
+ help="Log level",
120
+ )
108
121
 
109
122
  args = parser.parse_args()
110
123
 
@@ -143,4 +156,4 @@ def main() -> None:
143
156
 
144
157
 
145
158
  if __name__ == "__main__":
146
- main()
159
+ main()