mcp-proxy-adapter-dev 8.11.16__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 (644) hide show
  1. mcp_proxy_adapter/__init__.py +73 -0
  2. mcp_proxy_adapter/__main__.py +13 -0
  3. mcp_proxy_adapter/api/__init__.py +38 -0
  4. mcp_proxy_adapter/api/app.py +64 -0
  5. mcp_proxy_adapter/api/command_session_service.py +455 -0
  6. mcp_proxy_adapter/api/core/__init__.py +19 -0
  7. mcp_proxy_adapter/api/core/app_factory.py +215 -0
  8. mcp_proxy_adapter/api/core/app_factory_certificates.py +159 -0
  9. mcp_proxy_adapter/api/core/app_factory_config.py +75 -0
  10. mcp_proxy_adapter/api/core/app_factory_routes.py +345 -0
  11. mcp_proxy_adapter/api/core/app_factory_validators.py +165 -0
  12. mcp_proxy_adapter/api/core/lifespan_manager/__init__.py +52 -0
  13. mcp_proxy_adapter/api/core/lifespan_manager/manager.py +354 -0
  14. mcp_proxy_adapter/api/core/lifespan_manager/queue_config.py +37 -0
  15. mcp_proxy_adapter/api/core/lifespan_manager/signal_registration.py +74 -0
  16. mcp_proxy_adapter/api/core/registration/__init__.py +24 -0
  17. mcp_proxy_adapter/api/core/registration/config_parsers.py +247 -0
  18. mcp_proxy_adapter/api/core/registration/context_builder.py +130 -0
  19. mcp_proxy_adapter/api/core/registration/helpers.py +36 -0
  20. mcp_proxy_adapter/api/core/registration/metadata_builders.py +117 -0
  21. mcp_proxy_adapter/api/core/registration/models.py +42 -0
  22. mcp_proxy_adapter/api/core/registration/resolvers.py +195 -0
  23. mcp_proxy_adapter/api/core/registration/url_builders.py +122 -0
  24. mcp_proxy_adapter/api/core/registration_context.py +30 -0
  25. mcp_proxy_adapter/api/core/registration_manager/__init__.py +31 -0
  26. mcp_proxy_adapter/api/core/registration_manager/helpers.py +307 -0
  27. mcp_proxy_adapter/api/core/registration_manager/manager.py +584 -0
  28. mcp_proxy_adapter/api/core/registration_manager/status.py +152 -0
  29. mcp_proxy_adapter/api/core/registration_tasks.py +387 -0
  30. mcp_proxy_adapter/api/core/ssl_context_factory.py +99 -0
  31. mcp_proxy_adapter/api/execute_async_contract.py +124 -0
  32. mcp_proxy_adapter/api/handlers/__init__.py +335 -0
  33. mcp_proxy_adapter/api/handlers/command_execution.py +709 -0
  34. mcp_proxy_adapter/api/handlers/health.py +157 -0
  35. mcp_proxy_adapter/api/handlers/jsonrpc.py +207 -0
  36. mcp_proxy_adapter/api/handlers/transfer_notify.py +313 -0
  37. mcp_proxy_adapter/api/handlers/transfer_sessions.py +287 -0
  38. mcp_proxy_adapter/api/handlers_async.py +233 -0
  39. mcp_proxy_adapter/api/health_provider.py +44 -0
  40. mcp_proxy_adapter/api/jsonrpc_job_lifecycle.py +165 -0
  41. mcp_proxy_adapter/api/jsonrpc_job_status.py +94 -0
  42. mcp_proxy_adapter/api/middleware/__init__.py +14 -0
  43. mcp_proxy_adapter/api/middleware/command_permission_middleware.py +73 -0
  44. mcp_proxy_adapter/api/middleware/request_logging.py +153 -0
  45. mcp_proxy_adapter/api/middleware/unified_security.py +367 -0
  46. mcp_proxy_adapter/api/openapi/__init__.py +18 -0
  47. mcp_proxy_adapter/api/openapi/command_integration.py +107 -0
  48. mcp_proxy_adapter/api/openapi/openapi_generator.py +138 -0
  49. mcp_proxy_adapter/api/openapi/openapi_registry.py +55 -0
  50. mcp_proxy_adapter/api/public_downloads.py +68 -0
  51. mcp_proxy_adapter/api/schemas.py +290 -0
  52. mcp_proxy_adapter/api/tool_integration.py +124 -0
  53. mcp_proxy_adapter/api/tools.py +244 -0
  54. mcp_proxy_adapter/api/transfer_session_service.py +329 -0
  55. mcp_proxy_adapter/api/ws_endpoint.py +653 -0
  56. mcp_proxy_adapter/api/ws_identity.py +111 -0
  57. mcp_proxy_adapter/cli/__init__.py +12 -0
  58. mcp_proxy_adapter/cli/commands/__init__.py +14 -0
  59. mcp_proxy_adapter/cli/commands/client.py +137 -0
  60. mcp_proxy_adapter/cli/commands/config_docs/__init__.py +23 -0
  61. mcp_proxy_adapter/cli/commands/config_docs/cli.py +63 -0
  62. mcp_proxy_adapter/cli/commands/config_docs/declared_settings.py +45 -0
  63. mcp_proxy_adapter/cli/commands/config_docs/render.py +58 -0
  64. mcp_proxy_adapter/cli/commands/config_docs/sections/__init__.py +61 -0
  65. mcp_proxy_adapter/cli/commands/config_docs/sections/_chunk.py +19 -0
  66. mcp_proxy_adapter/cli/commands/config_docs/sections/authentication.py +127 -0
  67. mcp_proxy_adapter/cli/commands/config_docs/sections/best_practices.py +166 -0
  68. mcp_proxy_adapter/cli/commands/config_docs/sections/common_patterns.py +154 -0
  69. mcp_proxy_adapter/cli/commands/config_docs/sections/overview.py +135 -0
  70. mcp_proxy_adapter/cli/commands/config_docs/sections/queue_manager.py +140 -0
  71. mcp_proxy_adapter/cli/commands/config_docs/sections/registration.py +212 -0
  72. mcp_proxy_adapter/cli/commands/config_docs/sections/server.py +193 -0
  73. mcp_proxy_adapter/cli/commands/config_docs/sections/troubleshooting.py +215 -0
  74. mcp_proxy_adapter/cli/commands/config_generate.py +95 -0
  75. mcp_proxy_adapter/cli/commands/config_generate_parts/__init__.py +1 -0
  76. mcp_proxy_adapter/cli/commands/config_generate_parts/arguments.py +44 -0
  77. mcp_proxy_adapter/cli/commands/config_generate_parts/arguments_core.py +141 -0
  78. mcp_proxy_adapter/cli/commands/config_generate_parts/arguments_queue.py +140 -0
  79. mcp_proxy_adapter/cli/commands/config_generate_parts/arguments_validation.py +142 -0
  80. mcp_proxy_adapter/cli/commands/config_generate_parts/generation.py +365 -0
  81. mcp_proxy_adapter/cli/commands/config_generate_parts/parsing.py +122 -0
  82. mcp_proxy_adapter/cli/commands/config_validate.py +154 -0
  83. mcp_proxy_adapter/cli/commands/info.py +297 -0
  84. mcp_proxy_adapter/cli/commands/server.py +361 -0
  85. mcp_proxy_adapter/cli/commands/sets.py +165 -0
  86. mcp_proxy_adapter/cli/commands/standalone_entry.py +25 -0
  87. mcp_proxy_adapter/cli/commands/testconfig.py +205 -0
  88. mcp_proxy_adapter/cli/examples/__init__.py +9 -0
  89. mcp_proxy_adapter/cli/main.py +75 -0
  90. mcp_proxy_adapter/cli/parser.py +244 -0
  91. mcp_proxy_adapter/cli/validators.py +389 -0
  92. mcp_proxy_adapter/client/jsonrpc_client/__init__.py +139 -0
  93. mcp_proxy_adapter/client/jsonrpc_client/client.py +257 -0
  94. mcp_proxy_adapter/client/jsonrpc_client/command_api.py +369 -0
  95. mcp_proxy_adapter/client/jsonrpc_client/command_api_bases/__init__.py +1 -0
  96. mcp_proxy_adapter/client/jsonrpc_client/command_api_bases/async_base.py +241 -0
  97. mcp_proxy_adapter/client/jsonrpc_client/command_api_bases/basic_base.py +150 -0
  98. mcp_proxy_adapter/client/jsonrpc_client/command_api_bases/catalog_base.py +178 -0
  99. mcp_proxy_adapter/client/jsonrpc_client/command_api_bases/constants.py +38 -0
  100. mcp_proxy_adapter/client/jsonrpc_client/command_api_bases/helpers.py +66 -0
  101. mcp_proxy_adapter/client/jsonrpc_client/command_api_bases/queue_base.py +137 -0
  102. mcp_proxy_adapter/client/jsonrpc_client/exceptions/__init__.py +70 -0
  103. mcp_proxy_adapter/client/jsonrpc_client/exceptions/base.py +102 -0
  104. mcp_proxy_adapter/client/jsonrpc_client/exceptions/classification.py +143 -0
  105. mcp_proxy_adapter/client/jsonrpc_client/exceptions/request_errors.py +169 -0
  106. mcp_proxy_adapter/client/jsonrpc_client/exceptions/schema_errors.py +90 -0
  107. mcp_proxy_adapter/client/jsonrpc_client/exceptions/transfer_errors.py +48 -0
  108. mcp_proxy_adapter/client/jsonrpc_client/exceptions/transport_errors.py +153 -0
  109. mcp_proxy_adapter/client/jsonrpc_client/execution_status_observer.py +66 -0
  110. mcp_proxy_adapter/client/jsonrpc_client/job_event_registry.py +322 -0
  111. mcp_proxy_adapter/client/jsonrpc_client/job_tracking_mixin.py +206 -0
  112. mcp_proxy_adapter/client/jsonrpc_client/job_tracking_types.py +135 -0
  113. mcp_proxy_adapter/client/jsonrpc_client/openapi_validator.py +127 -0
  114. mcp_proxy_adapter/client/jsonrpc_client/operation_state.py +221 -0
  115. mcp_proxy_adapter/client/jsonrpc_client/proxy_api.py +93 -0
  116. mcp_proxy_adapter/client/jsonrpc_client/proxy_api_bases/__init__.py +1 -0
  117. mcp_proxy_adapter/client/jsonrpc_client/proxy_api_bases/client_base.py +117 -0
  118. mcp_proxy_adapter/client/jsonrpc_client/proxy_api_bases/lifecycle_base.py +222 -0
  119. mcp_proxy_adapter/client/jsonrpc_client/proxy_api_bases/register_base.py +230 -0
  120. mcp_proxy_adapter/client/jsonrpc_client/proxy_api_bases/uuid_base.py +95 -0
  121. mcp_proxy_adapter/client/jsonrpc_client/queue_api.py +302 -0
  122. mcp_proxy_adapter/client/jsonrpc_client/queue_status.py +192 -0
  123. mcp_proxy_adapter/client/jsonrpc_client/schema_generator.py +143 -0
  124. mcp_proxy_adapter/client/jsonrpc_client/schema_generator_bases/__init__.py +1 -0
  125. mcp_proxy_adapter/client/jsonrpc_client/schema_generator_bases/models.py +45 -0
  126. mcp_proxy_adapter/client/jsonrpc_client/schema_generator_bases/parse_base.py +215 -0
  127. mcp_proxy_adapter/client/jsonrpc_client/schema_generator_bases/validate_base.py +181 -0
  128. mcp_proxy_adapter/client/jsonrpc_client/transfer_integrity.py +57 -0
  129. mcp_proxy_adapter/client/jsonrpc_client/transport/__init__.py +161 -0
  130. mcp_proxy_adapter/client/jsonrpc_client/transport/constants.py +30 -0
  131. mcp_proxy_adapter/client/jsonrpc_client/transport/helpers.py +118 -0
  132. mcp_proxy_adapter/client/jsonrpc_client/transport/http_base.py +325 -0
  133. mcp_proxy_adapter/client/jsonrpc_client/transport/rpc_base.py +311 -0
  134. mcp_proxy_adapter/client/jsonrpc_client/transport/tls_base.py +295 -0
  135. mcp_proxy_adapter/client/jsonrpc_client/transport/transfer_base.py +282 -0
  136. mcp_proxy_adapter/client/jsonrpc_client/ws_command_session.py +230 -0
  137. mcp_proxy_adapter/client/jsonrpc_client/ws_command_session_bases/__init__.py +1 -0
  138. mcp_proxy_adapter/client/jsonrpc_client/ws_command_session_bases/core_base.py +154 -0
  139. mcp_proxy_adapter/client/jsonrpc_client/ws_command_session_bases/helpers.py +72 -0
  140. mcp_proxy_adapter/client/jsonrpc_client/ws_command_session_bases/wait_base.py +279 -0
  141. mcp_proxy_adapter/client/jsonrpc_client/ws_job_status.py +337 -0
  142. mcp_proxy_adapter/client/jsonrpc_client/ws_job_status_parts/__init__.py +1 -0
  143. mcp_proxy_adapter/client/jsonrpc_client/ws_job_status_parts/channel.py +159 -0
  144. mcp_proxy_adapter/client/jsonrpc_client/ws_job_status_parts/command_channel.py +154 -0
  145. mcp_proxy_adapter/client/jsonrpc_client/ws_job_status_parts/helpers.py +76 -0
  146. mcp_proxy_adapter/client/proxy.py +124 -0
  147. mcp_proxy_adapter/commands/__init__.py +27 -0
  148. mcp_proxy_adapter/commands/base.py +998 -0
  149. mcp_proxy_adapter/commands/builtin_commands.py +186 -0
  150. mcp_proxy_adapter/commands/command_help_info.py +101 -0
  151. mcp_proxy_adapter/commands/command_registry/__init__.py +55 -0
  152. mcp_proxy_adapter/commands/command_registry/builtins_part.py +206 -0
  153. mcp_proxy_adapter/commands/command_registry/facade.py +310 -0
  154. mcp_proxy_adapter/commands/command_registry/lifecycle_part.py +232 -0
  155. mcp_proxy_adapter/commands/command_registry/loader.py +145 -0
  156. mcp_proxy_adapter/commands/command_registry/mutations_part.py +228 -0
  157. mcp_proxy_adapter/commands/command_registry/part_base.py +59 -0
  158. mcp_proxy_adapter/commands/command_registry/queries_part.py +304 -0
  159. mcp_proxy_adapter/commands/config_command.py +208 -0
  160. mcp_proxy_adapter/commands/dependency_container.py +35 -0
  161. mcp_proxy_adapter/commands/echo_command.py +97 -0
  162. mcp_proxy_adapter/commands/health_command.py +162 -0
  163. mcp_proxy_adapter/commands/help_command.py +296 -0
  164. mcp_proxy_adapter/commands/hooks.py +590 -0
  165. mcp_proxy_adapter/commands/job_metadata.py +26 -0
  166. mcp_proxy_adapter/commands/load_command.py +134 -0
  167. mcp_proxy_adapter/commands/nested_validation.py +185 -0
  168. mcp_proxy_adapter/commands/plugins_command.py +250 -0
  169. mcp_proxy_adapter/commands/proxy_registration_command.py +475 -0
  170. mcp_proxy_adapter/commands/queue/__init__.py +83 -0
  171. mcp_proxy_adapter/commands/queue/add_job_command.py +358 -0
  172. mcp_proxy_adapter/commands/queue/command_execution_diagnostics.py +100 -0
  173. mcp_proxy_adapter/commands/queue/delete_job_command.py +92 -0
  174. mcp_proxy_adapter/commands/queue/get_logs_command.py +90 -0
  175. mcp_proxy_adapter/commands/queue/get_status_command.py +105 -0
  176. mcp_proxy_adapter/commands/queue/health_command.py +44 -0
  177. mcp_proxy_adapter/commands/queue/job_domain_errors.py +117 -0
  178. mcp_proxy_adapter/commands/queue/job_params.py +163 -0
  179. mcp_proxy_adapter/commands/queue/jobs/__init__.py +41 -0
  180. mcp_proxy_adapter/commands/queue/jobs/basic_jobs.py +205 -0
  181. mcp_proxy_adapter/commands/queue/jobs/command_execution_job.py +198 -0
  182. mcp_proxy_adapter/commands/queue/jobs/command_restore_base.py +48 -0
  183. mcp_proxy_adapter/commands/queue/jobs/command_run_base.py +389 -0
  184. mcp_proxy_adapter/commands/queue/jobs/job_helpers.py +80 -0
  185. mcp_proxy_adapter/commands/queue/jobs/long_jobs.py +257 -0
  186. mcp_proxy_adapter/commands/queue/list_jobs_command.py +127 -0
  187. mcp_proxy_adapter/commands/queue/start_job_command.py +97 -0
  188. mcp_proxy_adapter/commands/queue/stop_job_command.py +107 -0
  189. mcp_proxy_adapter/commands/queue_commands.py +49 -0
  190. mcp_proxy_adapter/commands/registration_status_command.py +83 -0
  191. mcp_proxy_adapter/commands/reload_command.py +183 -0
  192. mcp_proxy_adapter/commands/result.py +201 -0
  193. mcp_proxy_adapter/commands/result_helpers.py +43 -0
  194. mcp_proxy_adapter/commands/role_test_command.py +119 -0
  195. mcp_proxy_adapter/commands/roles_management_command/__init__.py +58 -0
  196. mcp_proxy_adapter/commands/roles_management_command/actions_part.py +400 -0
  197. mcp_proxy_adapter/commands/roles_management_command/dispatch_part.py +239 -0
  198. mcp_proxy_adapter/commands/roles_management_command/facade.py +233 -0
  199. mcp_proxy_adapter/commands/roles_management_command/part_base.py +61 -0
  200. mcp_proxy_adapter/commands/roles_management_command/results.py +105 -0
  201. mcp_proxy_adapter/commands/roles_management_command/storage_part.py +181 -0
  202. mcp_proxy_adapter/commands/schema_helpers.py +45 -0
  203. mcp_proxy_adapter/commands/settings_command.py +205 -0
  204. mcp_proxy_adapter/commands/transfer_command_support.py +83 -0
  205. mcp_proxy_adapter/commands/transfer_download_begin_command.py +245 -0
  206. mcp_proxy_adapter/commands/transfer_download_status_command.py +121 -0
  207. mcp_proxy_adapter/commands/transfer_schema_support.py +96 -0
  208. mcp_proxy_adapter/commands/transfer_upload_begin_command.py +254 -0
  209. mcp_proxy_adapter/commands/transfer_upload_complete_command.py +161 -0
  210. mcp_proxy_adapter/commands/transfer_upload_status_command.py +122 -0
  211. mcp_proxy_adapter/commands/transport_management_command.py +144 -0
  212. mcp_proxy_adapter/commands/unload_command.py +109 -0
  213. mcp_proxy_adapter/config.py +30 -0
  214. mcp_proxy_adapter/core/__init__.py +8 -0
  215. mcp_proxy_adapter/core/app_factory/__init__.py +17 -0
  216. mcp_proxy_adapter/core/app_factory/app_creator.py +66 -0
  217. mcp_proxy_adapter/core/app_factory/config_loader.py +125 -0
  218. mcp_proxy_adapter/core/app_factory/factory.py +158 -0
  219. mcp_proxy_adapter/core/app_factory/server_runner.py +152 -0
  220. mcp_proxy_adapter/core/app_factory/ssl_config.py +194 -0
  221. mcp_proxy_adapter/core/app_factory/validators.py +57 -0
  222. mcp_proxy_adapter/core/async_context.py +28 -0
  223. mcp_proxy_adapter/core/auth/__init__.py +18 -0
  224. mcp_proxy_adapter/core/auth/certificate_validator.py +239 -0
  225. mcp_proxy_adapter/core/auth/models.py +47 -0
  226. mcp_proxy_adapter/core/auth/mtls_validator.py +84 -0
  227. mcp_proxy_adapter/core/auth/token_validator.py +114 -0
  228. mcp_proxy_adapter/core/auth_validator.py +137 -0
  229. mcp_proxy_adapter/core/certificate/__init__.py +20 -0
  230. mcp_proxy_adapter/core/certificate/certificate_validator/__init__.py +55 -0
  231. mcp_proxy_adapter/core/certificate/certificate_validator/facade.py +340 -0
  232. mcp_proxy_adapter/core/certificate/certificate_validator/info_part.py +130 -0
  233. mcp_proxy_adapter/core/certificate/certificate_validator/key_part.py +146 -0
  234. mcp_proxy_adapter/core/certificate/certificate_validator/part_base.py +65 -0
  235. mcp_proxy_adapter/core/certificate/certificate_validator/revocation_part.py +112 -0
  236. mcp_proxy_adapter/core/client/__init__.py +11 -0
  237. mcp_proxy_adapter/core/client/auth_handler.py +120 -0
  238. mcp_proxy_adapter/core/client/client.py +314 -0
  239. mcp_proxy_adapter/core/client/factory.py +110 -0
  240. mcp_proxy_adapter/core/client/request_handler.py +122 -0
  241. mcp_proxy_adapter/core/client/ssl_handler.py +105 -0
  242. mcp_proxy_adapter/core/client_manager.py +281 -0
  243. mcp_proxy_adapter/core/client_security/__init__.py +53 -0
  244. mcp_proxy_adapter/core/client_security/auth_part.py +227 -0
  245. mcp_proxy_adapter/core/client_security/cert_part.py +124 -0
  246. mcp_proxy_adapter/core/client_security/facade.py +181 -0
  247. mcp_proxy_adapter/core/client_security/part_base.py +62 -0
  248. mcp_proxy_adapter/core/client_security/ssl_part.py +275 -0
  249. mcp_proxy_adapter/core/config/__init__.py +29 -0
  250. mcp_proxy_adapter/core/config/config.py +963 -0
  251. mcp_proxy_adapter/core/config/config_factory.py +16 -0
  252. mcp_proxy_adapter/core/config/config_graph.py +250 -0
  253. mcp_proxy_adapter/core/config/config_loader.py +70 -0
  254. mcp_proxy_adapter/core/config/env_placeholders.py +52 -0
  255. mcp_proxy_adapter/core/config/feature_manager.py +109 -0
  256. mcp_proxy_adapter/core/config/orchestration_section.py +119 -0
  257. mcp_proxy_adapter/core/config/reload_violations.py +269 -0
  258. mcp_proxy_adapter/core/config/section_validators.py +190 -0
  259. mcp_proxy_adapter/core/config/settings_declaration.py +255 -0
  260. mcp_proxy_adapter/core/config/simple_config.py +893 -0
  261. mcp_proxy_adapter/core/config/simple_config_generator.py +917 -0
  262. mcp_proxy_adapter/core/config/simple_config_validator.py +333 -0
  263. mcp_proxy_adapter/core/config/validators/__init__.py +29 -0
  264. mcp_proxy_adapter/core/config/validators/auth_validator.py +146 -0
  265. mcp_proxy_adapter/core/config/validators/base_validator.py +102 -0
  266. mcp_proxy_adapter/core/config/validators/certificate_validator_helper.py +114 -0
  267. mcp_proxy_adapter/core/config/validators/client_validator.py +131 -0
  268. mcp_proxy_adapter/core/config/validators/job_push_validator.py +55 -0
  269. mcp_proxy_adapter/core/config/validators/queue_manager_validator.py +133 -0
  270. mcp_proxy_adapter/core/config/validators/registration_validator.py +366 -0
  271. mcp_proxy_adapter/core/config/validators/server_validation_validator.py +154 -0
  272. mcp_proxy_adapter/core/config/validators/server_validator.py +326 -0
  273. mcp_proxy_adapter/core/config/validators/ssl_validator.py +221 -0
  274. mcp_proxy_adapter/core/config/websocket_validator.py +99 -0
  275. mcp_proxy_adapter/core/config_validator.py +29 -0
  276. mcp_proxy_adapter/core/constants.py +201 -0
  277. mcp_proxy_adapter/core/crl_utils.py +338 -0
  278. mcp_proxy_adapter/core/date_utils.py +119 -0
  279. mcp_proxy_adapter/core/delivery/__init__.py +35 -0
  280. mcp_proxy_adapter/core/delivery/contracts.py +57 -0
  281. mcp_proxy_adapter/core/delivery/exceptions.py +19 -0
  282. mcp_proxy_adapter/core/delivery/terminal_replay_store.py +129 -0
  283. mcp_proxy_adapter/core/delivery/ws_delivery_manager.py +117 -0
  284. mcp_proxy_adapter/core/domain_errors.py +189 -0
  285. mcp_proxy_adapter/core/error_handling.py +98 -0
  286. mcp_proxy_adapter/core/errors/__init__.py +259 -0
  287. mcp_proxy_adapter/core/errors/config_errors.py +142 -0
  288. mcp_proxy_adapter/core/file_utils.py +94 -0
  289. mcp_proxy_adapter/core/job_manager.py +115 -0
  290. mcp_proxy_adapter/core/job_push/__init__.py +124 -0
  291. mcp_proxy_adapter/core/job_push/caller_loss.py +89 -0
  292. mcp_proxy_adapter/core/job_push/engine.py +282 -0
  293. mcp_proxy_adapter/core/job_push/events/__init__.py +111 -0
  294. mcp_proxy_adapter/core/job_push/events/builders.py +282 -0
  295. mcp_proxy_adapter/core/job_push/events/command_session_payloads.py +50 -0
  296. mcp_proxy_adapter/core/job_push/events/delivery_payloads.py +52 -0
  297. mcp_proxy_adapter/core/job_push/events/event_names.py +163 -0
  298. mcp_proxy_adapter/core/job_push/events/job_payloads.py +83 -0
  299. mcp_proxy_adapter/core/job_push/events/transfer_payloads.py +72 -0
  300. mcp_proxy_adapter/core/job_push/execute_async_deliver_guard.py +55 -0
  301. mcp_proxy_adapter/core/job_push/finish_signal.py +91 -0
  302. mcp_proxy_adapter/core/job_push/hooks.py +53 -0
  303. mcp_proxy_adapter/core/job_push/job_status_accumulator.py +376 -0
  304. mcp_proxy_adapter/core/job_push/lifespan_wiring.py +252 -0
  305. mcp_proxy_adapter/core/job_push/notifier.py +139 -0
  306. mcp_proxy_adapter/core/job_push/notifier_policy.py +38 -0
  307. mcp_proxy_adapter/core/job_push/queue_custom_push.py +67 -0
  308. mcp_proxy_adapter/core/job_push/subscriptions.py +160 -0
  309. mcp_proxy_adapter/core/job_push/transfer_correlation.py +47 -0
  310. mcp_proxy_adapter/core/job_push/transfer_push.py +135 -0
  311. mcp_proxy_adapter/core/json_utils.py +81 -0
  312. mcp_proxy_adapter/core/logging/__init__.py +42 -0
  313. mcp_proxy_adapter/core/logging/formatters.py +55 -0
  314. mcp_proxy_adapter/core/logging/global_logger.py +41 -0
  315. mcp_proxy_adapter/core/logging/request_logger.py +50 -0
  316. mcp_proxy_adapter/core/logging/setup.py +190 -0
  317. mcp_proxy_adapter/core/logging/worker.py +107 -0
  318. mcp_proxy_adapter/core/mtls_asgi_app.py +216 -0
  319. mcp_proxy_adapter/core/mtls_server.py +180 -0
  320. mcp_proxy_adapter/core/orchestration/__init__.py +90 -0
  321. mcp_proxy_adapter/core/orchestration/candidate_validator.py +196 -0
  322. mcp_proxy_adapter/core/orchestration/catalog_builder.py +136 -0
  323. mcp_proxy_adapter/core/orchestration/catalog_snapshot.py +115 -0
  324. mcp_proxy_adapter/core/orchestration/command_record.py +43 -0
  325. mcp_proxy_adapter/core/orchestration/discovery_client.py +229 -0
  326. mcp_proxy_adapter/core/orchestration/orchestration_api.py +273 -0
  327. mcp_proxy_adapter/core/orchestration/orchestration_config.py +146 -0
  328. mcp_proxy_adapter/core/orchestration/orchestration_errors.py +305 -0
  329. mcp_proxy_adapter/core/orchestration/orchestration_lifespan.py +199 -0
  330. mcp_proxy_adapter/core/orchestration/parameter_graph.py +106 -0
  331. mcp_proxy_adapter/core/orchestration/polling_loop.py +281 -0
  332. mcp_proxy_adapter/core/orchestration/server_record.py +37 -0
  333. mcp_proxy_adapter/core/orchestration/snapshot_holder.py +90 -0
  334. mcp_proxy_adapter/core/orchestration/tool_context_exposure.py +83 -0
  335. mcp_proxy_adapter/core/orchestration/tool_context_snapshot.py +164 -0
  336. mcp_proxy_adapter/core/path_utils.py +220 -0
  337. mcp_proxy_adapter/core/protocol_manager.py +260 -0
  338. mcp_proxy_adapter/core/proxy/__init__.py +62 -0
  339. mcp_proxy_adapter/core/proxy/auth_manager.py +110 -0
  340. mcp_proxy_adapter/core/proxy_client.py +252 -0
  341. mcp_proxy_adapter/core/proxy_registration.py +55 -0
  342. mcp_proxy_adapter/core/role_utils.py +166 -0
  343. mcp_proxy_adapter/core/server_adapter.py +302 -0
  344. mcp_proxy_adapter/core/server_engine.py +384 -0
  345. mcp_proxy_adapter/core/settings.py +299 -0
  346. mcp_proxy_adapter/core/signal_handler.py +136 -0
  347. mcp_proxy_adapter/core/ssl_utils.py +482 -0
  348. mcp_proxy_adapter/core/transport_manager.py +168 -0
  349. mcp_proxy_adapter/core/utils.py +74 -0
  350. mcp_proxy_adapter/core/validation/__init__.py +21 -0
  351. mcp_proxy_adapter/core/validation/config_validator.py +256 -0
  352. mcp_proxy_adapter/core/validation/file_validator.py +229 -0
  353. mcp_proxy_adapter/core/validation/protocol_validator.py +322 -0
  354. mcp_proxy_adapter/core/validation/proxy_registration_validator.py +268 -0
  355. mcp_proxy_adapter/core/validation/security_validator.py +300 -0
  356. mcp_proxy_adapter/core/validation/validation_result.py +34 -0
  357. mcp_proxy_adapter/core/validation/validator_support.py +64 -0
  358. mcp_proxy_adapter/core/validation_utils.py +160 -0
  359. mcp_proxy_adapter/core/ws_timeouts.py +88 -0
  360. mcp_proxy_adapter/custom_openapi.py +93 -0
  361. mcp_proxy_adapter/examples/PROTOCOL_EXAMPLES.md +79 -0
  362. mcp_proxy_adapter/examples/README.md +272 -0
  363. mcp_proxy_adapter/examples/README_EN.md +258 -0
  364. mcp_proxy_adapter/examples/SECURITY_TESTING.md +455 -0
  365. mcp_proxy_adapter/examples/__init__.py +16 -0
  366. mcp_proxy_adapter/examples/basic_framework/__init__.py +9 -0
  367. mcp_proxy_adapter/examples/basic_framework/commands/__init__.py +4 -0
  368. mcp_proxy_adapter/examples/basic_framework/configs/http_auth.json +21 -0
  369. mcp_proxy_adapter/examples/basic_framework/configs/http_simple.json +21 -0
  370. mcp_proxy_adapter/examples/basic_framework/configs/https_auth.json +21 -0
  371. mcp_proxy_adapter/examples/basic_framework/configs/https_no_protocol_middleware.json +21 -0
  372. mcp_proxy_adapter/examples/basic_framework/configs/https_simple.json +21 -0
  373. mcp_proxy_adapter/examples/basic_framework/configs/mtls_no_protocol_middleware.json +21 -0
  374. mcp_proxy_adapter/examples/basic_framework/configs/mtls_no_roles.json +21 -0
  375. mcp_proxy_adapter/examples/basic_framework/configs/mtls_simple.json +21 -0
  376. mcp_proxy_adapter/examples/basic_framework/configs/mtls_with_registration.json +73 -0
  377. mcp_proxy_adapter/examples/basic_framework/configs/mtls_with_roles.json +21 -0
  378. mcp_proxy_adapter/examples/basic_framework/hooks/__init__.py +4 -0
  379. mcp_proxy_adapter/examples/basic_framework/main.py +123 -0
  380. mcp_proxy_adapter/examples/basic_framework/roles.json +1 -0
  381. mcp_proxy_adapter/examples/bug_report_security_framework.md +141 -0
  382. mcp_proxy_adapter/examples/cert_config.json +1 -0
  383. mcp_proxy_adapter/examples/certs/cert_config.json +1 -0
  384. mcp_proxy_adapter/examples/check_config.py +71 -0
  385. mcp_proxy_adapter/examples/check_config_split_parts/__init__.py +3 -0
  386. mcp_proxy_adapter/examples/check_config_split_parts/checker.py +247 -0
  387. mcp_proxy_adapter/examples/check_config_split_parts/cli.py +68 -0
  388. mcp_proxy_adapter/examples/check_config_split_parts/commands.py +102 -0
  389. mcp_proxy_adapter/examples/cli_config_examples/__init__.py +8 -0
  390. mcp_proxy_adapter/examples/cli_config_examples/examples_configs/http.json +69 -0
  391. mcp_proxy_adapter/examples/cli_config_examples/examples_configs/https_token_roles.json +84 -0
  392. mcp_proxy_adapter/examples/cli_config_examples/examples_configs/mtls_roles.json +84 -0
  393. mcp_proxy_adapter/examples/cli_config_examples/http_basic.py +97 -0
  394. mcp_proxy_adapter/examples/cli_config_examples/https_token.py +128 -0
  395. mcp_proxy_adapter/examples/cli_config_examples/mtls_roles.py +140 -0
  396. mcp_proxy_adapter/examples/client_configs/api_key_client.json +1 -0
  397. mcp_proxy_adapter/examples/client_configs/basic_auth_client.json +1 -0
  398. mcp_proxy_adapter/examples/client_configs/certificate_client.json +1 -0
  399. mcp_proxy_adapter/examples/client_configs/jwt_client.json +1 -0
  400. mcp_proxy_adapter/examples/client_configs/no_auth_client.json +1 -0
  401. mcp_proxy_adapter/examples/client_usage_example.py +216 -0
  402. mcp_proxy_adapter/examples/commands/__init__.py +5 -0
  403. mcp_proxy_adapter/examples/comprehensive/__init__.py +10 -0
  404. mcp_proxy_adapter/examples/comprehensive/run.py +906 -0
  405. mcp_proxy_adapter/examples/comprehensive_config.json +10 -0
  406. mcp_proxy_adapter/examples/config.json +10 -0
  407. mcp_proxy_adapter/examples/config_builder.py +272 -0
  408. mcp_proxy_adapter/examples/config_cli.py +340 -0
  409. mcp_proxy_adapter/examples/config_factory.py +325 -0
  410. mcp_proxy_adapter/examples/configs/full_featured.json +10 -0
  411. mcp_proxy_adapter/examples/configs/http_auth.json +10 -0
  412. mcp_proxy_adapter/examples/configs/http_simple.json +10 -0
  413. mcp_proxy_adapter/examples/configs/http_token.json +10 -0
  414. mcp_proxy_adapter/examples/configs/https_auth.json +10 -0
  415. mcp_proxy_adapter/examples/configs/https_simple.json +10 -0
  416. mcp_proxy_adapter/examples/configs/https_token.json +10 -0
  417. mcp_proxy_adapter/examples/configs/mtls_no_roles.json +10 -0
  418. mcp_proxy_adapter/examples/configs/mtls_simple.json +10 -0
  419. mcp_proxy_adapter/examples/configs/mtls_with_proxy.json +10 -0
  420. mcp_proxy_adapter/examples/configs/mtls_with_roles.json +10 -0
  421. mcp_proxy_adapter/examples/configs/roles.json +1 -0
  422. mcp_proxy_adapter/examples/create_test_configs.py +216 -0
  423. mcp_proxy_adapter/examples/debug_role_chain.py +192 -0
  424. mcp_proxy_adapter/examples/demo_client.py +339 -0
  425. mcp_proxy_adapter/examples/examples_correct/http_example.json +10 -0
  426. mcp_proxy_adapter/examples/full_application/__init__.py +11 -0
  427. mcp_proxy_adapter/examples/full_application/commands/__init__.py +32 -0
  428. mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +75 -0
  429. mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +101 -0
  430. mcp_proxy_adapter/examples/full_application/commands/embed_job_status_command.py +133 -0
  431. mcp_proxy_adapter/examples/full_application/commands/embed_queue_command.py +153 -0
  432. mcp_proxy_adapter/examples/full_application/commands/long_running_command.py +175 -0
  433. mcp_proxy_adapter/examples/full_application/commands/slow_start_long_task_command.py +172 -0
  434. mcp_proxy_adapter/examples/full_application/configs/http_basic.json +73 -0
  435. mcp_proxy_adapter/examples/full_application/configs/http_basic_smart_assistant_proxy3004.json +67 -0
  436. mcp_proxy_adapter/examples/full_application/configs/http_no_registration.json +72 -0
  437. mcp_proxy_adapter/examples/full_application/configs/http_token.json +69 -0
  438. mcp_proxy_adapter/examples/full_application/configs/http_token_roles.json +81 -0
  439. mcp_proxy_adapter/examples/full_application/configs/http_token_roles_smart_assistant_proxy3004.json +81 -0
  440. mcp_proxy_adapter/examples/full_application/configs/http_token_smart_assistant_proxy3004.json +69 -0
  441. mcp_proxy_adapter/examples/full_application/configs/https_basic.json +74 -0
  442. mcp_proxy_adapter/examples/full_application/configs/https_basic_smart_assistant_proxy3004.json +81 -0
  443. mcp_proxy_adapter/examples/full_application/configs/https_token.json +76 -0
  444. mcp_proxy_adapter/examples/full_application/configs/https_token_roles.json +88 -0
  445. mcp_proxy_adapter/examples/full_application/configs/https_token_roles_smart_assistant_proxy3004.json +95 -0
  446. mcp_proxy_adapter/examples/full_application/configs/https_token_smart_assistant_proxy3004.json +83 -0
  447. mcp_proxy_adapter/examples/full_application/configs/mtls_no_roles.json +78 -0
  448. mcp_proxy_adapter/examples/full_application/configs/mtls_no_roles_correct.json +76 -0
  449. mcp_proxy_adapter/examples/full_application/configs/mtls_no_roles_smart_assistant_proxy3004.json +83 -0
  450. mcp_proxy_adapter/examples/full_application/configs/mtls_no_security.json +77 -0
  451. mcp_proxy_adapter/examples/full_application/configs/mtls_with_roles.json +82 -0
  452. mcp_proxy_adapter/examples/full_application/configs/mtls_with_roles_correct.json +88 -0
  453. mcp_proxy_adapter/examples/full_application/configs/mtls_with_roles_smart_assistant_proxy3004.json +95 -0
  454. mcp_proxy_adapter/examples/full_application/configs/mtls_ws_repro.json +76 -0
  455. mcp_proxy_adapter/examples/full_application/configs/proxy_server.json +64 -0
  456. mcp_proxy_adapter/examples/full_application/configs/proxy_server_https.json +63 -0
  457. mcp_proxy_adapter/examples/full_application/configs/proxy_server_mtls.json +63 -0
  458. mcp_proxy_adapter/examples/full_application/example_support.py +45 -0
  459. mcp_proxy_adapter/examples/full_application/hooks/__init__.py +4 -0
  460. mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +51 -0
  461. mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +46 -0
  462. mcp_proxy_adapter/examples/full_application/main.py +95 -0
  463. mcp_proxy_adapter/examples/full_application/main_modules/__init__.py +1 -0
  464. mcp_proxy_adapter/examples/full_application/main_modules/registration.py +122 -0
  465. mcp_proxy_adapter/examples/full_application/main_modules/runner.py +310 -0
  466. mcp_proxy_adapter/examples/full_application/proxy_commands/__init__.py +113 -0
  467. mcp_proxy_adapter/examples/full_application/proxy_commands/_shared.py +8 -0
  468. mcp_proxy_adapter/examples/full_application/proxy_commands/lifecycle_commands.py +196 -0
  469. mcp_proxy_adapter/examples/full_application/proxy_commands/register_command.py +254 -0
  470. mcp_proxy_adapter/examples/full_application/proxy_commands/registry_state.py +8 -0
  471. mcp_proxy_adapter/examples/full_application/proxy_commands/results.py +142 -0
  472. mcp_proxy_adapter/examples/full_application/proxy_endpoints.py +162 -0
  473. mcp_proxy_adapter/examples/full_application/proxy_schemas.py +91 -0
  474. mcp_proxy_adapter/examples/full_application/roles.json +1 -0
  475. mcp_proxy_adapter/examples/full_application/test_client.py +341 -0
  476. mcp_proxy_adapter/examples/full_application/test_minimal_server.py +57 -0
  477. mcp_proxy_adapter/examples/full_application/test_queue_and_descriptions.py +283 -0
  478. mcp_proxy_adapter/examples/full_application/test_server.py +221 -0
  479. mcp_proxy_adapter/examples/full_application/test_simple_server.py +141 -0
  480. mcp_proxy_adapter/examples/generate_all_certificates.py +74 -0
  481. mcp_proxy_adapter/examples/generate_config.py +44 -0
  482. mcp_proxy_adapter/examples/generate_config_parts/__init__.py +3 -0
  483. mcp_proxy_adapter/examples/generate_config_parts/builders.py +234 -0
  484. mcp_proxy_adapter/examples/generate_config_parts/cli.py +260 -0
  485. mcp_proxy_adapter/examples/generate_config_parts/outputs.py +137 -0
  486. mcp_proxy_adapter/examples/generator_validator_compatibility_report.md +127 -0
  487. mcp_proxy_adapter/examples/http_proxy_example.json +17 -0
  488. mcp_proxy_adapter/examples/https_proxy_example.json +17 -0
  489. mcp_proxy_adapter/examples/job_tracking_demo.py +235 -0
  490. mcp_proxy_adapter/examples/proxy_server_support.py +384 -0
  491. mcp_proxy_adapter/examples/queue_demo_simple.py +37 -0
  492. mcp_proxy_adapter/examples/queue_demo_simple_parts/__init__.py +3 -0
  493. mcp_proxy_adapter/examples/queue_demo_simple_parts/_shared.py +8 -0
  494. mcp_proxy_adapter/examples/queue_demo_simple_parts/demo.py +213 -0
  495. mcp_proxy_adapter/examples/queue_demo_simple_parts/mock_commands.py +130 -0
  496. mcp_proxy_adapter/examples/queue_demo_simple_parts/mock_manager.py +272 -0
  497. mcp_proxy_adapter/examples/queue_example_support.py +36 -0
  498. mcp_proxy_adapter/examples/queue_fire_and_forget_example.py +370 -0
  499. mcp_proxy_adapter/examples/queue_server_demo.py +73 -0
  500. mcp_proxy_adapter/examples/queue_server_example.py +76 -0
  501. mcp_proxy_adapter/examples/queue_server_simple.py +251 -0
  502. mcp_proxy_adapter/examples/required_certificates.py +216 -0
  503. mcp_proxy_adapter/examples/run_example.py +119 -0
  504. mcp_proxy_adapter/examples/run_full_test_suite.py +674 -0
  505. mcp_proxy_adapter/examples/run_proxy_server.py +118 -0
  506. mcp_proxy_adapter/examples/run_security_tests_fixed.py +876 -0
  507. mcp_proxy_adapter/examples/security_test/__init__.py +18 -0
  508. mcp_proxy_adapter/examples/security_test/auth_manager.py +49 -0
  509. mcp_proxy_adapter/examples/security_test/ssl_context_manager.py +144 -0
  510. mcp_proxy_adapter/examples/security_test/test_client.py +218 -0
  511. mcp_proxy_adapter/examples/security_test/test_result.py +23 -0
  512. mcp_proxy_adapter/examples/security_test_client.py +103 -0
  513. mcp_proxy_adapter/examples/server_configs/config_basic_http.json +16 -0
  514. mcp_proxy_adapter/examples/server_configs/config_http_token.json +16 -0
  515. mcp_proxy_adapter/examples/server_configs/config_https.json +16 -0
  516. mcp_proxy_adapter/examples/server_configs/config_https_token.json +16 -0
  517. mcp_proxy_adapter/examples/server_configs/config_mtls.json +16 -0
  518. mcp_proxy_adapter/examples/server_configs/config_proxy_registration.json +15 -0
  519. mcp_proxy_adapter/examples/server_configs/config_simple.json +9 -0
  520. mcp_proxy_adapter/examples/server_configs/http_simple.json +14 -0
  521. mcp_proxy_adapter/examples/server_configs/http_token.json +14 -0
  522. mcp_proxy_adapter/examples/server_configs/https_simple.json +14 -0
  523. mcp_proxy_adapter/examples/server_configs/https_token.json +14 -0
  524. mcp_proxy_adapter/examples/server_configs/mtls_no_roles.json +8 -0
  525. mcp_proxy_adapter/examples/server_configs/mtls_test.json +8 -0
  526. mcp_proxy_adapter/examples/server_configs/mtls_with_roles.json +14 -0
  527. mcp_proxy_adapter/examples/server_configs/roles.json +1 -0
  528. mcp_proxy_adapter/examples/setup/__init__.py +48 -0
  529. mcp_proxy_adapter/examples/setup/certificate_manager.py +384 -0
  530. mcp_proxy_adapter/examples/setup/config_generator.py +6 -0
  531. mcp_proxy_adapter/examples/setup/config_validator.py +140 -0
  532. mcp_proxy_adapter/examples/setup/environment_setup.py +143 -0
  533. mcp_proxy_adapter/examples/setup/test_files_generator.py +6 -0
  534. mcp_proxy_adapter/examples/setup/test_runner.py +143 -0
  535. mcp_proxy_adapter/examples/setup_test_environment.py +233 -0
  536. mcp_proxy_adapter/examples/simple_http_example.json +17 -0
  537. mcp_proxy_adapter/examples/simple_https_example.json +17 -0
  538. mcp_proxy_adapter/examples/simple_protocol_test.py +167 -0
  539. mcp_proxy_adapter/examples/test_client/README.md +166 -0
  540. mcp_proxy_adapter/examples/test_client/__init__.py +7 -0
  541. mcp_proxy_adapter/examples/test_client/main.py +102 -0
  542. mcp_proxy_adapter/examples/test_client/main_split_parts/__init__.py +1 -0
  543. mcp_proxy_adapter/examples/test_client/main_split_parts/helpers.py +83 -0
  544. mcp_proxy_adapter/examples/test_client/main_split_parts/runner.py +115 -0
  545. mcp_proxy_adapter/examples/test_client/main_split_parts/scenarios.py +195 -0
  546. mcp_proxy_adapter/examples/test_config.py +183 -0
  547. mcp_proxy_adapter/examples/test_configs/custom_https.json +10 -0
  548. mcp_proxy_adapter/examples/test_configs/http_simple.json +10 -0
  549. mcp_proxy_adapter/examples/test_examples.py +361 -0
  550. mcp_proxy_adapter/examples/test_mcp_server.py +249 -0
  551. mcp_proxy_adapter/examples/test_protocol_examples.py +373 -0
  552. mcp_proxy_adapter/examples/test_proxy/README.md +70 -0
  553. mcp_proxy_adapter/examples/test_proxy/__init__.py +7 -0
  554. mcp_proxy_adapter/examples/test_proxy/main.py +106 -0
  555. mcp_proxy_adapter/examples/test_server/README.md +58 -0
  556. mcp_proxy_adapter/examples/test_server/__init__.py +7 -0
  557. mcp_proxy_adapter/examples/test_server/main.py +349 -0
  558. mcp_proxy_adapter/examples/transparent_queue_commands.py +281 -0
  559. mcp_proxy_adapter/examples/transparent_queue_e1_sync_call.py +102 -0
  560. mcp_proxy_adapter/examples/transparent_queue_e2_event_stream.py +134 -0
  561. mcp_proxy_adapter/examples/transparent_queue_e3_ws_timeouts.py +341 -0
  562. mcp_proxy_adapter/examples/transparent_queue_e4_ws_fallback.py +159 -0
  563. mcp_proxy_adapter/examples/transparent_queue_e5_inner_failure.py +189 -0
  564. mcp_proxy_adapter/examples/transparent_queue_e6_atomic_state.py +203 -0
  565. mcp_proxy_adapter/examples/transparent_queue_e7_caller_loss.py +63 -0
  566. mcp_proxy_adapter/examples/transparent_queue_e7_split2/__init__.py +3 -0
  567. mcp_proxy_adapter/examples/transparent_queue_e7_split2/cases.py +335 -0
  568. mcp_proxy_adapter/examples/transparent_queue_e7_split2/helpers.py +66 -0
  569. mcp_proxy_adapter/examples/transparent_queue_support.py +377 -0
  570. mcp_proxy_adapter/examples/unified_error_handling_example.py +127 -0
  571. mcp_proxy_adapter/examples/unified_error_handling_split_parts/__init__.py +3 -0
  572. mcp_proxy_adapter/examples/unified_error_handling_split_parts/demos.py +180 -0
  573. mcp_proxy_adapter/examples/unified_error_handling_split_parts/runner.py +109 -0
  574. mcp_proxy_adapter/examples/unified_error_handling_split_parts/support.py +79 -0
  575. mcp_proxy_adapter/examples/unified_error_handling_texts.py +17 -0
  576. mcp_proxy_adapter/examples/universal_client.py +215 -0
  577. mcp_proxy_adapter/examples/universal_client_split_parts/__init__.py +3 -0
  578. mcp_proxy_adapter/examples/universal_client_split_parts/configs.py +104 -0
  579. mcp_proxy_adapter/examples/universal_client_split_parts/demos.py +144 -0
  580. mcp_proxy_adapter/examples/update_config_certificates.py +156 -0
  581. mcp_proxy_adapter/examples/validate_generator_compatibility_simple.py +60 -0
  582. mcp_proxy_adapter/examples/websocket_examples/__init__.py +8 -0
  583. mcp_proxy_adapter/examples/websocket_examples/client_bidirectional_websocket.py +100 -0
  584. mcp_proxy_adapter/examples/websocket_examples/client_websocket_job_status.py +103 -0
  585. mcp_proxy_adapter/examples/websocket_examples/run_ws_test_server.py +157 -0
  586. mcp_proxy_adapter/examples/ws_examples/__init__.py +6 -0
  587. mcp_proxy_adapter/examples/ws_examples/http_basic_ws.py +68 -0
  588. mcp_proxy_adapter/examples/ws_examples/http_token_roles_ws.py +66 -0
  589. mcp_proxy_adapter/examples/ws_examples/http_token_ws.py +80 -0
  590. mcp_proxy_adapter/examples/ws_examples/https_basic_ws.py +61 -0
  591. mcp_proxy_adapter/examples/ws_examples/https_token_roles_ws.py +67 -0
  592. mcp_proxy_adapter/examples/ws_examples/https_token_ws.py +64 -0
  593. mcp_proxy_adapter/examples/ws_examples/mtls_basic_ws.py +94 -0
  594. mcp_proxy_adapter/examples/ws_examples/mtls_roles_ws.py +88 -0
  595. mcp_proxy_adapter/examples/ws_examples/ws_example_runner.py +233 -0
  596. mcp_proxy_adapter/integrations/__init__.py +31 -0
  597. mcp_proxy_adapter/integrations/queuemgr_integration/__init__.py +124 -0
  598. mcp_proxy_adapter/integrations/queuemgr_integration/_compat.py +60 -0
  599. mcp_proxy_adapter/integrations/queuemgr_integration/_health.py +299 -0
  600. mcp_proxy_adapter/integrations/queuemgr_integration/_limits.py +70 -0
  601. mcp_proxy_adapter/integrations/queuemgr_integration/_process_reap.py +232 -0
  602. mcp_proxy_adapter/integrations/queuemgr_integration/_result_builders.py +119 -0
  603. mcp_proxy_adapter/integrations/queuemgr_integration/_status_helpers.py +167 -0
  604. mcp_proxy_adapter/integrations/queuemgr_integration/global_manager.py +174 -0
  605. mcp_proxy_adapter/integrations/queuemgr_integration/job_types/__init__.py +375 -0
  606. mcp_proxy_adapter/integrations/queuemgr_integration/job_types/value_types.py +97 -0
  607. mcp_proxy_adapter/integrations/queuemgr_integration/job_types/worker_probe.py +29 -0
  608. mcp_proxy_adapter/integrations/queuemgr_integration/manager/__init__.py +52 -0
  609. mcp_proxy_adapter/integrations/queuemgr_integration/manager/fallback_base.py +240 -0
  610. mcp_proxy_adapter/integrations/queuemgr_integration/manager/fallback_stop_base.py +179 -0
  611. mcp_proxy_adapter/integrations/queuemgr_integration/manager/health_base.py +460 -0
  612. mcp_proxy_adapter/integrations/queuemgr_integration/manager/integration.py +189 -0
  613. mcp_proxy_adapter/integrations/queuemgr_integration/manager/job_start_base.py +333 -0
  614. mcp_proxy_adapter/integrations/queuemgr_integration/manager/job_stop_base.py +274 -0
  615. mcp_proxy_adapter/integrations/queuemgr_integration/manager/lifecycle_base.py +393 -0
  616. mcp_proxy_adapter/integrations/queuemgr_integration/manager/query_base.py +269 -0
  617. mcp_proxy_adapter/integrations/queuemgr_registration.py +66 -0
  618. mcp_proxy_adapter/integrations/queuemgr_version.py +39 -0
  619. mcp_proxy_adapter/main.py +385 -0
  620. mcp_proxy_adapter/main_ssl_paths.py +29 -0
  621. mcp_proxy_adapter/py.typed +0 -0
  622. mcp_proxy_adapter/schemas/base_schema.json +114 -0
  623. mcp_proxy_adapter/schemas/openapi_schema.json +269 -0
  624. mcp_proxy_adapter/schemas/roles.json +37 -0
  625. mcp_proxy_adapter/schemas/roles_schema.json +162 -0
  626. mcp_proxy_adapter/transfer/__init__.py +56 -0
  627. mcp_proxy_adapter/transfer/checksums.py +81 -0
  628. mcp_proxy_adapter/transfer/client_downloader/__init__.py +37 -0
  629. mcp_proxy_adapter/transfer/client_downloader/download_support.py +109 -0
  630. mcp_proxy_adapter/transfer/client_downloader/downloader.py +300 -0
  631. mcp_proxy_adapter/transfer/client_uploader.py +278 -0
  632. mcp_proxy_adapter/transfer/compression.py +127 -0
  633. mcp_proxy_adapter/transfer/errors.py +253 -0
  634. mcp_proxy_adapter/transfer/json_coerce.py +32 -0
  635. mcp_proxy_adapter/transfer/models.py +337 -0
  636. mcp_proxy_adapter/transfer/path_confinement.py +69 -0
  637. mcp_proxy_adapter/transfer/progress_percent.py +25 -0
  638. mcp_proxy_adapter/transfer/server_store.py +878 -0
  639. mcp_proxy_adapter/version.py +8 -0
  640. mcp_proxy_adapter_dev-8.11.16.dist-info/METADATA +1666 -0
  641. mcp_proxy_adapter_dev-8.11.16.dist-info/RECORD +644 -0
  642. mcp_proxy_adapter_dev-8.11.16.dist-info/WHEEL +5 -0
  643. mcp_proxy_adapter_dev-8.11.16.dist-info/entry_points.txt +12 -0
  644. mcp_proxy_adapter_dev-8.11.16.dist-info/top_level.txt +1 -0
@@ -0,0 +1,73 @@
1
+ """MCP Proxy API Service package.
2
+
3
+ This package provides a framework for creating JSON-RPC-enabled microservices.
4
+ """
5
+
6
+ from typing import Any, Callable, Optional
7
+
8
+ from mcp_proxy_adapter.commands.base import Command
9
+ from mcp_proxy_adapter.commands.command_registry import registry
10
+ from mcp_proxy_adapter.commands.result import CommandResult, ErrorResult, SuccessResult
11
+ from mcp_proxy_adapter.core.errors import (
12
+ CommandError,
13
+ InternalError,
14
+ InvalidParamsError,
15
+ MicroserviceError,
16
+ NotFoundError,
17
+ TimeoutError,
18
+ ValidationError,
19
+ )
20
+ from mcp_proxy_adapter.version import __version__
21
+
22
+
23
+ # `create_app` is deliberately NOT imported at module level (bug 7f7ce943):
24
+ # `mcp_proxy_adapter.api.app` pulls in the whole route/websocket stack
25
+ # (api.core.app_factory -> app_factory_routes -> ws_endpoint ->
26
+ # command_session_service -> commands.queue), and `commands/queue/__init__.py`
27
+ # and `core/server_engine.py` both run command/engine registration AS AN
28
+ # IMPORT-TIME SIDE EFFECT that logs at INFO. Since `import mcp_proxy_adapter`
29
+ # always executes this file first (Python imports parent packages before any
30
+ # submodule), that eager import meant every CLI invocation - including plain
31
+ # `--help` - and every downstream library import inherited ten unsolicited
32
+ # log lines before doing anything. `__getattr__` below (PEP 562) defers the
33
+ # import to the first real access, so `from mcp_proxy_adapter import
34
+ # create_app` keeps working unchanged for real server startups (which still
35
+ # log exactly as before, since building an app is precisely when a server
36
+ # needs its commands and engine registered), while `--help` and any
37
+ # import that never touches `create_app` stay clean.
38
+ def __getattr__(name: str) -> Any:
39
+ if name == "create_app":
40
+ from mcp_proxy_adapter.api.app import create_app as _create_app
41
+
42
+ return _create_app
43
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
44
+
45
+
46
+ # CLI module
47
+ # Delayed import of CLI to avoid side effects during server startup
48
+ # CLI can be accessed via entrypoint `mcp-proxy-adapter` or `python -m mcp_proxy_adapter`
49
+ cli_main: Optional[Callable[[], int]]
50
+ try:
51
+ from mcp_proxy_adapter.cli import main as cli_main
52
+ except Exception:
53
+ # Avoid import errors impacting library/server usage
54
+ cli_main = None
55
+
56
+ # Экспортируем основные классы и функции для удобного использования
57
+ __all__ = [
58
+ "__version__",
59
+ "create_app",
60
+ "Command",
61
+ "CommandResult",
62
+ "SuccessResult",
63
+ "ErrorResult",
64
+ "registry",
65
+ "MicroserviceError",
66
+ "CommandError",
67
+ "ValidationError",
68
+ "InvalidParamsError",
69
+ "NotFoundError",
70
+ "TimeoutError",
71
+ "InternalError",
72
+ "cli_main",
73
+ ]
@@ -0,0 +1,13 @@
1
+ """
2
+ MCP Proxy Adapter CLI Entry Point
3
+
4
+ This module allows running the CLI using: python -m mcp_proxy_adapter
5
+
6
+ Author: Vasiliy Zdanovskiy
7
+ email: vasilyvz@gmail.com
8
+ """
9
+
10
+ from .cli.main import main
11
+
12
+ if __name__ == "__main__":
13
+ main()
@@ -0,0 +1,38 @@
1
+ """
2
+ API module for MCP Proxy Adapter.
3
+
4
+ This module provides FastAPI application setup, handlers, middleware,
5
+ and OpenAPI integration for the MCP Proxy Adapter framework.
6
+
7
+ Author: Vasiliy Zdanovskiy
8
+ email: vasilyvz@gmail.com
9
+ """
10
+
11
+ from typing import Any
12
+
13
+ __all__ = [
14
+ "set_health_provider",
15
+ "get_health_provider",
16
+ ]
17
+
18
+
19
+ def __getattr__(name: str) -> Any:
20
+ """Lazy import of health provider to defer module-level imports.
21
+
22
+ This implements PEP 562 to make health_provider available but not loaded
23
+ on bare package import. The health provider is server-only and should
24
+ not be eagerly imported by client code.
25
+ """
26
+ if name in ("set_health_provider", "get_health_provider"):
27
+ from mcp_proxy_adapter.api.health_provider import (
28
+ get_health_provider,
29
+ set_health_provider,
30
+ )
31
+
32
+ return (
33
+ set_health_provider
34
+ if name == "set_health_provider"
35
+ else get_health_provider
36
+ )
37
+
38
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
@@ -0,0 +1,64 @@
1
+ """
2
+ Module for FastAPI application setup.
3
+ """
4
+
5
+ from typing import Any, AsyncContextManager, Callable, Dict, Optional
6
+
7
+ from fastapi import FastAPI
8
+
9
+ from .core import AppFactory, LifespanManager, SSLContextFactory
10
+
11
+
12
+ def create_lifespan(
13
+ config_path: Optional[str] = None, current_config: Optional[Dict[str, Any]] = None
14
+ ) -> Callable[[FastAPI], AsyncContextManager[None]]:
15
+ """
16
+ Create lifespan manager for the FastAPI application.
17
+
18
+ Args:
19
+ config_path: Path to configuration file (optional)
20
+ current_config: Current configuration data (optional)
21
+
22
+ Returns:
23
+ Lifespan context manager
24
+ """
25
+ lifespan_manager = LifespanManager()
26
+ return lifespan_manager.create_lifespan(config_path, current_config)
27
+
28
+
29
+ def create_ssl_context(app_config: Optional[Dict[str, Any]] = None) -> Optional[Any]:
30
+ """
31
+ Create SSL context based on configuration.
32
+
33
+ Args:
34
+ app_config: Application configuration dictionary (optional)
35
+
36
+ Returns:
37
+ SSL context if SSL is enabled and properly configured, None otherwise
38
+ """
39
+ ssl_factory = SSLContextFactory()
40
+ return ssl_factory.create_ssl_context(app_config)
41
+
42
+
43
+ def create_app(
44
+ title: Optional[str] = None,
45
+ description: Optional[str] = None,
46
+ version: Optional[str] = None,
47
+ app_config: Optional[Dict[str, Any]] = None,
48
+ config_path: Optional[str] = None,
49
+ ) -> FastAPI:
50
+ """
51
+ Creates and configures FastAPI application.
52
+
53
+ Args:
54
+ title: Application title (default: "MCP Proxy Adapter")
55
+ description: Application description (default: "JSON-RPC API for interacting with MCP Proxy")
56
+ version: Application version (default: "1.0.0")
57
+ app_config: Application configuration dictionary (optional)
58
+ config_path: Path to configuration file (optional)
59
+
60
+ Returns:
61
+ Configured FastAPI application.
62
+ """
63
+ app_factory = AppFactory()
64
+ return app_factory.create_app(title, description, version, app_config, config_path)
@@ -0,0 +1,455 @@
1
+ """Enqueue-first command-session service for WebSocket command execution."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+ import uuid
7
+ from dataclasses import dataclass
8
+ from typing import Any, Dict, Mapping, Optional
9
+
10
+ from mcp_proxy_adapter.api import handlers as _handlers_pkg
11
+ from mcp_proxy_adapter.api.middleware.command_permission_middleware import (
12
+ check_command_permission,
13
+ )
14
+ from mcp_proxy_adapter.commands.command_registry import registry
15
+ from mcp_proxy_adapter.commands.queue.job_params import (
16
+ build_command_execution_job_params,
17
+ )
18
+ from mcp_proxy_adapter.commands.queue.jobs import CommandExecutionJob
19
+ from mcp_proxy_adapter.core.errors import MethodNotFoundError, ValidationError
20
+ from mcp_proxy_adapter.core.job_push.events import (
21
+ build_command_accepted_message,
22
+ build_command_error_message,
23
+ build_command_session_result_rpc,
24
+ )
25
+ from mcp_proxy_adapter.core.job_push.subscriptions import SubscriptionCategory
26
+ from mcp_proxy_adapter.core.logging import get_global_logger
27
+ from mcp_proxy_adapter.integrations.queuemgr_integration import (
28
+ get_global_queue_manager,
29
+ )
30
+ from mcp_proxy_adapter.integrations.queuemgr_integration._process_reap import (
31
+ _is_emfile_error,
32
+ )
33
+
34
+
35
+ @dataclass(frozen=True)
36
+ class CommandSessionMetadata:
37
+ """Correlation metadata for a WS-started command."""
38
+
39
+ request_id: str
40
+ job_id: str
41
+ command: str
42
+ identity: Dict[str, Any]
43
+ result_channel: str = "rpc"
44
+
45
+ @property
46
+ def result_rpc(self) -> Dict[str, Any]:
47
+ """RPC reference used by terminal command-session events."""
48
+ return build_command_session_result_rpc(self.job_id)
49
+
50
+
51
+ @dataclass(frozen=True)
52
+ class CommandSessionAccepted:
53
+ """Accepted command-session response."""
54
+
55
+ metadata: CommandSessionMetadata
56
+ accepted_event: Dict[str, Any]
57
+
58
+
59
+ _metadata_lock = asyncio.Lock()
60
+ _metadata_by_job_id: Dict[str, CommandSessionMetadata] = {}
61
+ _cleanup_tasks: Dict[str, asyncio.Task[None]] = {}
62
+
63
+
64
+ def _identity_log_fields(identity: Mapping[str, Any]) -> str:
65
+ """
66
+ Render a command-session caller's identity as structured ``key=value``
67
+ text for a log line (bug 4322fb83: the "Command session job ... started"
68
+ log line carried job_id+command only, with no caller/origin, leaving
69
+ forensics blind to who invoked a session-executed command - e.g. which
70
+ principal issued ``stop_worker``/``start_worker`` during an unexplained
71
+ restart window).
72
+
73
+ Reads only what the call path already genuinely has -
74
+ ``get_identity_from_scope`` (``api/ws_identity.py``, the one real
75
+ identity source for WS-started command sessions today) always sets
76
+ ``type`` to one of "token", "mtls", or "anonymous", plus whichever of
77
+ ``user_id``/``role`` (token) or ``cn``/``fingerprint`` (mtls) it managed
78
+ to read. No field is invented here: an absent value is left out of the
79
+ line entirely rather than printed as a placeholder, and a caller with no
80
+ identity at all (``type`` missing, e.g. a non-WS caller that never
81
+ passed ``identity=``) renders explicitly as ``caller_type=anonymous``
82
+ rather than silently dropping the field.
83
+
84
+ Args:
85
+ identity: The command session's ``identity`` mapping (empty dict if
86
+ the caller never supplied one).
87
+
88
+ Returns:
89
+ A single space-joined ``key=value`` string, e.g.
90
+ ``"caller_type=token user_id=abc123 role=admin"`` or
91
+ ``"caller_type=anonymous"``.
92
+ """
93
+ caller_type = identity.get("type") or "anonymous"
94
+ fields = [f"caller_type={caller_type}"]
95
+ for key in ("user_id", "role", "cn", "fingerprint"):
96
+ value = identity.get(key)
97
+ if value is not None:
98
+ fields.append(f"{key}={value}")
99
+ return " ".join(fields)
100
+
101
+
102
+ def _normalize_request_id(request_id: Optional[str]) -> str:
103
+ """Return stripped request_id or generate new UUID if missing or empty."""
104
+ if request_id is not None and str(request_id).strip():
105
+ return str(request_id).strip()
106
+ return str(uuid.uuid4())
107
+
108
+
109
+ def _normalize_params(params: Optional[Mapping[str, Any]]) -> Dict[str, Any]:
110
+ """Convert params to dict; raise ValidationError if not a mapping or None."""
111
+ if params is None:
112
+ return {}
113
+ if not isinstance(params, Mapping):
114
+ raise ValidationError("command params must be an object")
115
+ return dict(params)
116
+
117
+
118
+ async def _remember_metadata(metadata: CommandSessionMetadata) -> None:
119
+ """Store metadata and cancel any existing cleanup task for this job."""
120
+ async with _metadata_lock:
121
+ old_task = _cleanup_tasks.pop(metadata.job_id, None)
122
+ if old_task is not None and not old_task.done():
123
+ old_task.cancel()
124
+ _metadata_by_job_id[metadata.job_id] = metadata
125
+
126
+
127
+ async def get_command_session_metadata(
128
+ job_id: str,
129
+ ) -> Optional[CommandSessionMetadata]:
130
+ """Return metadata for a command-session job, if still retained."""
131
+ jid = str(job_id).strip()
132
+ if not jid:
133
+ return None
134
+ async with _metadata_lock:
135
+ return _metadata_by_job_id.get(jid)
136
+
137
+
138
+ async def forget_command_session_metadata(job_id: str) -> None:
139
+ """Forget retained command-session metadata for *job_id*."""
140
+ jid = str(job_id).strip()
141
+ if not jid:
142
+ return
143
+ async with _metadata_lock:
144
+ _metadata_by_job_id.pop(jid, None)
145
+ task = _cleanup_tasks.pop(jid, None)
146
+ if task is not None and not task.done():
147
+ task.cancel()
148
+
149
+
150
+ async def schedule_command_session_metadata_cleanup(
151
+ job_id: str,
152
+ ttl_seconds: float = 3600.0,
153
+ ) -> None:
154
+ """Schedule metadata cleanup after a terminal event replay window."""
155
+ jid = str(job_id).strip()
156
+ if not jid:
157
+ return
158
+
159
+ async def _cleanup() -> None:
160
+ """Sleep for TTL then remove metadata and task from tracking dicts."""
161
+ await asyncio.sleep(max(0.0, float(ttl_seconds)))
162
+ async with _metadata_lock:
163
+ _metadata_by_job_id.pop(jid, None)
164
+ _cleanup_tasks.pop(jid, None)
165
+
166
+ async with _metadata_lock:
167
+ existing = _cleanup_tasks.pop(jid, None)
168
+ if existing is not None and not existing.done():
169
+ existing.cancel()
170
+ _cleanup_tasks[jid] = asyncio.create_task(_cleanup())
171
+
172
+
173
+ async def start_command_session(
174
+ *,
175
+ command: str,
176
+ params: Optional[Mapping[str, Any]],
177
+ context: Optional[Mapping[str, Any]],
178
+ request_id: Optional[str],
179
+ identity: Optional[Mapping[str, Any]] = None,
180
+ result_channel: str = "rpc",
181
+ config: Optional[Mapping[str, Any]] = None,
182
+ app_state: Optional[Any] = None,
183
+ ) -> CommandSessionAccepted:
184
+ """Enqueue a command for isolated execution and return acceptance metadata.
185
+
186
+ Args:
187
+ app_state: The caller's ``FastAPI`` ``app.state`` (e.g.
188
+ ``ctx.app.state`` from ``ws_endpoint.py``), used only if
189
+ ``queue_manager.start_job`` fails in the background (bug
190
+ 83afa2ba) - see ``_start_job_background``'s except block, which
191
+ reads ``job_push_registry``/``job_status_accumulator`` off it to
192
+ deliver a terminal ``command_error`` the same way
193
+ ``core/job_push/lifespan_wiring.py`` delivers any other terminal
194
+ command-session event. Optional and best-effort: a caller that
195
+ omits it (e.g. existing tests) only loses that terminal push,
196
+ never breaks the enqueue-first happy path this function's
197
+ return value is about.
198
+ """
199
+ command_name = str(command or "").strip()
200
+ if not command_name:
201
+ raise ValidationError("execute_command requires non-empty command")
202
+ command_params = _normalize_params(params)
203
+ command_params.pop("poll_interval", None)
204
+ command_params.pop("max_wait_time", None)
205
+ command_context: Dict[str, Any] = dict(context or {})
206
+ identity_dict: Dict[str, Any] = dict(identity or {})
207
+ rid = _normalize_request_id(request_id)
208
+ result_channel_name = "rpc"
209
+
210
+ try:
211
+ command_class = registry.get_command(command_name)
212
+ except Exception as exc:
213
+ raise MethodNotFoundError(f"Method not found: {command_name}") from exc
214
+
215
+ user_context = command_context.get("user")
216
+ user_mapping = user_context if isinstance(user_context, Mapping) else None
217
+ if not check_command_permission(command_name, user_mapping, config=config):
218
+ raise ValidationError(
219
+ f"Not allowed to execute command: {command_name}",
220
+ data={"command": command_name},
221
+ )
222
+
223
+ queue_manager = await get_global_queue_manager()
224
+ job_id = str(uuid.uuid4())
225
+
226
+ metadata = CommandSessionMetadata(
227
+ request_id=rid,
228
+ job_id=job_id,
229
+ command=command_name,
230
+ identity=identity_dict,
231
+ result_channel=result_channel_name,
232
+ )
233
+ await _remember_metadata(metadata)
234
+
235
+ logger = get_global_logger()
236
+
237
+ identity_fields = _identity_log_fields(identity_dict)
238
+
239
+ # Bug 0d64b41c (owner's ruling, option b): honour `use_queue` on the
240
+ # unified/WS command-session path exactly as the sync `execute_command`
241
+ # path already does (api/handlers/command_execution.py) - a command
242
+ # whose class does NOT set `use_queue=True` must run IN THIS SERVER
243
+ # PROCESS, not in a queuemgr spawn-mode worker (a fresh interpreter with
244
+ # NO access to this process's in-memory state: session registries,
245
+ # caches, module-level objects - see docs/HOWTO_CUSTOM_COMMANDS_SPAWN_MODE.md).
246
+ use_queue = getattr(command_class, "use_queue", False)
247
+
248
+ if use_queue:
249
+ # Bug cf5d11f7: validate BEFORE enqueue, exactly as the JSON-RPC path
250
+ # does (api/handlers/command_execution.py), so a refusal is immediate
251
+ # and no job is created. A ValidationError propagates to the caller.
252
+ registry.get_command_instance(command_name).validate_params(command_params)
253
+ job_params = build_command_execution_job_params(
254
+ command_name, command_params, command_context
255
+ )
256
+ await queue_manager.add_job(CommandExecutionJob, job_id, job_params)
257
+
258
+ async def _start_job_background() -> None:
259
+ """Start job in queue manager and log result or error.
260
+
261
+ The log lines below carry the caller's identity/origin and the
262
+ request_id (bug 4322fb83) - both already available as parameters to
263
+ ``start_command_session`` (``identity_dict``/``rid``) - so a
264
+ forensic read of the log can attribute who started a given
265
+ session-executed command, not just which job/command ran.
266
+ """
267
+ try:
268
+ await queue_manager.start_job(job_id)
269
+ logger.info(
270
+ "Command session job %s (command=%s) started request_id=%s %s",
271
+ job_id,
272
+ command_name,
273
+ rid,
274
+ identity_fields,
275
+ )
276
+ except Exception as exc:
277
+ # A caller may cancel an accepted job while its background
278
+ # start is still waiting for admission. Native start then
279
+ # refuses the already-stopped job; that is a successful
280
+ # cancellation, not a failed start to overwrite and delete.
281
+ from mcp_proxy_adapter.core.job_push.caller_loss import (
282
+ cancel_reason_for,
283
+ )
284
+
285
+ if cancel_reason_for(job_id) is not None:
286
+ try:
287
+ current = await queue_manager.get_job_status(job_id)
288
+ except Exception as status_exc:
289
+ logger.debug(
290
+ "Command session job %s: reading cancellation "
291
+ "state after start refusal failed: %s",
292
+ job_id,
293
+ status_exc,
294
+ )
295
+ else:
296
+ if current.status == "stopped":
297
+ engine = getattr(app_state, "job_push_engine", None)
298
+ if engine is not None and hasattr(engine, "watch"):
299
+ engine.watch(job_id)
300
+ if hasattr(engine, "wake"):
301
+ engine.wake(job_id)
302
+ logger.info(
303
+ "Command session job %s start superseded by "
304
+ "cancellation reason=%s request_id=%s %s",
305
+ job_id,
306
+ cancel_reason_for(job_id),
307
+ rid,
308
+ identity_fields,
309
+ )
310
+ return
311
+ # Bug 83afa2ba: queuemgr's start_job never mutates job status on
312
+ # a failed start, so without the recovery below the job stays
313
+ # "pending" forever and a plain queue_get_job_status poller (or
314
+ # a WS command-session subscriber) waits indefinitely for an
315
+ # event that will never arrive. Recover on all three surfaces a
316
+ # caller might be watching: push a terminal command_error to any
317
+ # live COMMAND_SESSION subscribers, record it in the
318
+ # accumulator so a late/resumed subscriber sees it too, and
319
+ # best-effort delete the job so a plain status poller observes
320
+ # a terminal (DELETED) status instead of stalling on "pending".
321
+ is_emfile = _is_emfile_error(exc)
322
+ logger.warning(
323
+ "Command session job %s (command=%s) start failed%s: %s "
324
+ "request_id=%s %s",
325
+ job_id,
326
+ command_name,
327
+ " (EMFILE/too many open files)" if is_emfile else "",
328
+ exc,
329
+ rid,
330
+ identity_fields,
331
+ )
332
+ command_error = build_command_error_message(
333
+ error=str(exc),
334
+ job_id=job_id,
335
+ request_id=rid,
336
+ command=command_name,
337
+ status="failed",
338
+ result_channel=metadata.result_channel,
339
+ )
340
+ if app_state is not None:
341
+ acc = getattr(app_state, "job_status_accumulator", None)
342
+ if acc is not None and hasattr(acc, "record_command_session"):
343
+ try:
344
+ await acc.record_command_session(job_id, command_error)
345
+ except Exception as acc_exc:
346
+ logger.debug(
347
+ "Command session job %s: recording start-failure "
348
+ "terminal event in accumulator failed: %s",
349
+ job_id,
350
+ acc_exc,
351
+ )
352
+ push_registry = getattr(app_state, "job_push_registry", None)
353
+ if push_registry is not None:
354
+ try:
355
+ subscribers = await push_registry.get_subscribers(
356
+ job_id, SubscriptionCategory.COMMAND_SESSION
357
+ )
358
+ except Exception as reg_exc:
359
+ logger.debug(
360
+ "Command session job %s: fetching subscribers for "
361
+ "start-failure terminal push failed: %s",
362
+ job_id,
363
+ reg_exc,
364
+ )
365
+ subscribers = []
366
+ for sub in subscribers:
367
+ try:
368
+ await sub.send(command_error)
369
+ except Exception as send_exc:
370
+ logger.warning(
371
+ "Command session start-failure terminal push "
372
+ "failed for job_id=%s: %s",
373
+ job_id,
374
+ send_exc,
375
+ )
376
+ await forget_command_session_metadata(job_id)
377
+ try:
378
+ await queue_manager.delete_job(job_id)
379
+ except Exception as delete_exc:
380
+ logger.debug(
381
+ "Command session job %s: best-effort delete after start "
382
+ "failure failed: %s",
383
+ job_id,
384
+ delete_exc,
385
+ )
386
+
387
+ asyncio.create_task(_start_job_background())
388
+ else:
389
+ # IN-PROCESS BRANCH (bug 0d64b41c). Reuses the exact call the sync
390
+ # dispatcher's own non-queue branch makes
391
+ # (api/handlers/command_execution.py execute_command(), "Legacy
392
+ # sync-start behavior": ``command_class.run(**params,
393
+ # context=context)``) so parameter validation (``Command.run()`` ->
394
+ # ``validate_params()``), context handling and the error envelope
395
+ # (a raised ``ValidationError``/``CommandError`` inside ``execute()``
396
+ # becomes an ``ErrorResult``, never an uncaught exception) are
397
+ # IDENTICAL on both paths - nothing here re-implements or forks that
398
+ # logic. ``asyncio.create_task`` runs it as a task that does not
399
+ # block this WS handler.
400
+ #
401
+ # The task is tracked the SAME way command_execution.py's own
402
+ # sync-cap timeout fallback already tracks a command that must keep
403
+ # running in-process (bug e3b822d4): registered on the queue
404
+ # manager's adapter-side detached-fallback-job store under THIS
405
+ # job_id via ``register_detached_fallback_job`` /
406
+ # ``_attach_detached_fallback_completion`` (shared with
407
+ # ``_handle_sync_timeout_fallback``), so ``queue_get_job_status`` /
408
+ # ``queue_list_jobs`` / ``queue_stop_job`` / ``queue_delete_job`` all
409
+ # already handle it correctly with NO new code, and the existing job-
410
+ # push poll loop (``core/job_push/lifespan_wiring.py``
411
+ # ``_job_push_poll_loop``, which already drives the terminal
412
+ # command-session event for a QUEUED job by polling
413
+ # ``queue_manager.get_job_status``) delivers the terminal
414
+ # command-session event through the SAME ``COMMAND_SESSION``
415
+ # subscription this WS session already holds
416
+ # (``ws_endpoint.py`` ``_handle_execute_command`` subscribes
417
+ # unconditionally, before branching here) - no separate delivery
418
+ # path is added for the in-process case.
419
+ #
420
+ # job_id / stop / cancel semantics for an in-process run: ``job_id``
421
+ # identifies this adapter-side store record, not a queuemgr job.
422
+ # ``queue_stop_job`` NEVER cancels it
423
+ # (``QueueManagerIntegration._stop_detached_fallback_job``):
424
+ # cancelling a running coroutine mid-flight here is exactly the
425
+ # request-body-corruption trigger bug e3b822d4 already documents for
426
+ # the sync-cap fallback, so a stop answers honestly that the command
427
+ # is running in-process, cannot be interrupted, and will publish its
428
+ # own terminal result. ``queue_delete_job`` simply stops tracking
429
+ # the record; the execution itself always runs to completion.
430
+ run_task: "asyncio.Future[Any]" = asyncio.create_task(
431
+ command_class.run(**command_params, context=command_context)
432
+ )
433
+ queue_manager.register_detached_fallback_job(
434
+ job_id, command_name, run_task, cancellable=True
435
+ )
436
+ _handlers_pkg._attach_detached_fallback_completion(
437
+ run_task, queue_manager, job_id, command_name, logger
438
+ )
439
+ logger.info(
440
+ "Command session job %s (command=%s) started in-process "
441
+ "(use_queue=False) request_id=%s %s",
442
+ job_id,
443
+ command_name,
444
+ rid,
445
+ identity_fields,
446
+ )
447
+
448
+ accepted_event = build_command_accepted_message(
449
+ job_id=job_id,
450
+ request_id=rid,
451
+ command=command_name,
452
+ status="pending",
453
+ result_channel=metadata.result_channel,
454
+ )
455
+ return CommandSessionAccepted(metadata=metadata, accepted_event=accepted_event)
@@ -0,0 +1,19 @@
1
+ """
2
+ Author: Vasiliy Zdanovskiy
3
+ email: vasilyvz@gmail.com
4
+
5
+ Core API utilities for MCP Proxy Adapter.
6
+ """
7
+
8
+ from .app_factory import AppFactory
9
+ from .lifespan_manager import LifespanManager
10
+ from .registration_manager import RegistrationManager, RegistrationSetupError
11
+ from .ssl_context_factory import SSLContextFactory
12
+
13
+ __all__ = [
14
+ "AppFactory",
15
+ "SSLContextFactory",
16
+ "RegistrationManager",
17
+ "RegistrationSetupError",
18
+ "LifespanManager",
19
+ ]