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.
- mcp_proxy_adapter/__init__.py +73 -0
- mcp_proxy_adapter/__main__.py +13 -0
- mcp_proxy_adapter/api/__init__.py +38 -0
- mcp_proxy_adapter/api/app.py +64 -0
- mcp_proxy_adapter/api/command_session_service.py +455 -0
- mcp_proxy_adapter/api/core/__init__.py +19 -0
- mcp_proxy_adapter/api/core/app_factory.py +215 -0
- mcp_proxy_adapter/api/core/app_factory_certificates.py +159 -0
- mcp_proxy_adapter/api/core/app_factory_config.py +75 -0
- mcp_proxy_adapter/api/core/app_factory_routes.py +345 -0
- mcp_proxy_adapter/api/core/app_factory_validators.py +165 -0
- mcp_proxy_adapter/api/core/lifespan_manager/__init__.py +52 -0
- mcp_proxy_adapter/api/core/lifespan_manager/manager.py +354 -0
- mcp_proxy_adapter/api/core/lifespan_manager/queue_config.py +37 -0
- mcp_proxy_adapter/api/core/lifespan_manager/signal_registration.py +74 -0
- mcp_proxy_adapter/api/core/registration/__init__.py +24 -0
- mcp_proxy_adapter/api/core/registration/config_parsers.py +247 -0
- mcp_proxy_adapter/api/core/registration/context_builder.py +130 -0
- mcp_proxy_adapter/api/core/registration/helpers.py +36 -0
- mcp_proxy_adapter/api/core/registration/metadata_builders.py +117 -0
- mcp_proxy_adapter/api/core/registration/models.py +42 -0
- mcp_proxy_adapter/api/core/registration/resolvers.py +195 -0
- mcp_proxy_adapter/api/core/registration/url_builders.py +122 -0
- mcp_proxy_adapter/api/core/registration_context.py +30 -0
- mcp_proxy_adapter/api/core/registration_manager/__init__.py +31 -0
- mcp_proxy_adapter/api/core/registration_manager/helpers.py +307 -0
- mcp_proxy_adapter/api/core/registration_manager/manager.py +584 -0
- mcp_proxy_adapter/api/core/registration_manager/status.py +152 -0
- mcp_proxy_adapter/api/core/registration_tasks.py +387 -0
- mcp_proxy_adapter/api/core/ssl_context_factory.py +99 -0
- mcp_proxy_adapter/api/execute_async_contract.py +124 -0
- mcp_proxy_adapter/api/handlers/__init__.py +335 -0
- mcp_proxy_adapter/api/handlers/command_execution.py +709 -0
- mcp_proxy_adapter/api/handlers/health.py +157 -0
- mcp_proxy_adapter/api/handlers/jsonrpc.py +207 -0
- mcp_proxy_adapter/api/handlers/transfer_notify.py +313 -0
- mcp_proxy_adapter/api/handlers/transfer_sessions.py +287 -0
- mcp_proxy_adapter/api/handlers_async.py +233 -0
- mcp_proxy_adapter/api/health_provider.py +44 -0
- mcp_proxy_adapter/api/jsonrpc_job_lifecycle.py +165 -0
- mcp_proxy_adapter/api/jsonrpc_job_status.py +94 -0
- mcp_proxy_adapter/api/middleware/__init__.py +14 -0
- mcp_proxy_adapter/api/middleware/command_permission_middleware.py +73 -0
- mcp_proxy_adapter/api/middleware/request_logging.py +153 -0
- mcp_proxy_adapter/api/middleware/unified_security.py +367 -0
- mcp_proxy_adapter/api/openapi/__init__.py +18 -0
- mcp_proxy_adapter/api/openapi/command_integration.py +107 -0
- mcp_proxy_adapter/api/openapi/openapi_generator.py +138 -0
- mcp_proxy_adapter/api/openapi/openapi_registry.py +55 -0
- mcp_proxy_adapter/api/public_downloads.py +68 -0
- mcp_proxy_adapter/api/schemas.py +290 -0
- mcp_proxy_adapter/api/tool_integration.py +124 -0
- mcp_proxy_adapter/api/tools.py +244 -0
- mcp_proxy_adapter/api/transfer_session_service.py +329 -0
- mcp_proxy_adapter/api/ws_endpoint.py +653 -0
- mcp_proxy_adapter/api/ws_identity.py +111 -0
- mcp_proxy_adapter/cli/__init__.py +12 -0
- mcp_proxy_adapter/cli/commands/__init__.py +14 -0
- mcp_proxy_adapter/cli/commands/client.py +137 -0
- mcp_proxy_adapter/cli/commands/config_docs/__init__.py +23 -0
- mcp_proxy_adapter/cli/commands/config_docs/cli.py +63 -0
- mcp_proxy_adapter/cli/commands/config_docs/declared_settings.py +45 -0
- mcp_proxy_adapter/cli/commands/config_docs/render.py +58 -0
- mcp_proxy_adapter/cli/commands/config_docs/sections/__init__.py +61 -0
- mcp_proxy_adapter/cli/commands/config_docs/sections/_chunk.py +19 -0
- mcp_proxy_adapter/cli/commands/config_docs/sections/authentication.py +127 -0
- mcp_proxy_adapter/cli/commands/config_docs/sections/best_practices.py +166 -0
- mcp_proxy_adapter/cli/commands/config_docs/sections/common_patterns.py +154 -0
- mcp_proxy_adapter/cli/commands/config_docs/sections/overview.py +135 -0
- mcp_proxy_adapter/cli/commands/config_docs/sections/queue_manager.py +140 -0
- mcp_proxy_adapter/cli/commands/config_docs/sections/registration.py +212 -0
- mcp_proxy_adapter/cli/commands/config_docs/sections/server.py +193 -0
- mcp_proxy_adapter/cli/commands/config_docs/sections/troubleshooting.py +215 -0
- mcp_proxy_adapter/cli/commands/config_generate.py +95 -0
- mcp_proxy_adapter/cli/commands/config_generate_parts/__init__.py +1 -0
- mcp_proxy_adapter/cli/commands/config_generate_parts/arguments.py +44 -0
- mcp_proxy_adapter/cli/commands/config_generate_parts/arguments_core.py +141 -0
- mcp_proxy_adapter/cli/commands/config_generate_parts/arguments_queue.py +140 -0
- mcp_proxy_adapter/cli/commands/config_generate_parts/arguments_validation.py +142 -0
- mcp_proxy_adapter/cli/commands/config_generate_parts/generation.py +365 -0
- mcp_proxy_adapter/cli/commands/config_generate_parts/parsing.py +122 -0
- mcp_proxy_adapter/cli/commands/config_validate.py +154 -0
- mcp_proxy_adapter/cli/commands/info.py +297 -0
- mcp_proxy_adapter/cli/commands/server.py +361 -0
- mcp_proxy_adapter/cli/commands/sets.py +165 -0
- mcp_proxy_adapter/cli/commands/standalone_entry.py +25 -0
- mcp_proxy_adapter/cli/commands/testconfig.py +205 -0
- mcp_proxy_adapter/cli/examples/__init__.py +9 -0
- mcp_proxy_adapter/cli/main.py +75 -0
- mcp_proxy_adapter/cli/parser.py +244 -0
- mcp_proxy_adapter/cli/validators.py +389 -0
- mcp_proxy_adapter/client/jsonrpc_client/__init__.py +139 -0
- mcp_proxy_adapter/client/jsonrpc_client/client.py +257 -0
- mcp_proxy_adapter/client/jsonrpc_client/command_api.py +369 -0
- mcp_proxy_adapter/client/jsonrpc_client/command_api_bases/__init__.py +1 -0
- mcp_proxy_adapter/client/jsonrpc_client/command_api_bases/async_base.py +241 -0
- mcp_proxy_adapter/client/jsonrpc_client/command_api_bases/basic_base.py +150 -0
- mcp_proxy_adapter/client/jsonrpc_client/command_api_bases/catalog_base.py +178 -0
- mcp_proxy_adapter/client/jsonrpc_client/command_api_bases/constants.py +38 -0
- mcp_proxy_adapter/client/jsonrpc_client/command_api_bases/helpers.py +66 -0
- mcp_proxy_adapter/client/jsonrpc_client/command_api_bases/queue_base.py +137 -0
- mcp_proxy_adapter/client/jsonrpc_client/exceptions/__init__.py +70 -0
- mcp_proxy_adapter/client/jsonrpc_client/exceptions/base.py +102 -0
- mcp_proxy_adapter/client/jsonrpc_client/exceptions/classification.py +143 -0
- mcp_proxy_adapter/client/jsonrpc_client/exceptions/request_errors.py +169 -0
- mcp_proxy_adapter/client/jsonrpc_client/exceptions/schema_errors.py +90 -0
- mcp_proxy_adapter/client/jsonrpc_client/exceptions/transfer_errors.py +48 -0
- mcp_proxy_adapter/client/jsonrpc_client/exceptions/transport_errors.py +153 -0
- mcp_proxy_adapter/client/jsonrpc_client/execution_status_observer.py +66 -0
- mcp_proxy_adapter/client/jsonrpc_client/job_event_registry.py +322 -0
- mcp_proxy_adapter/client/jsonrpc_client/job_tracking_mixin.py +206 -0
- mcp_proxy_adapter/client/jsonrpc_client/job_tracking_types.py +135 -0
- mcp_proxy_adapter/client/jsonrpc_client/openapi_validator.py +127 -0
- mcp_proxy_adapter/client/jsonrpc_client/operation_state.py +221 -0
- mcp_proxy_adapter/client/jsonrpc_client/proxy_api.py +93 -0
- mcp_proxy_adapter/client/jsonrpc_client/proxy_api_bases/__init__.py +1 -0
- mcp_proxy_adapter/client/jsonrpc_client/proxy_api_bases/client_base.py +117 -0
- mcp_proxy_adapter/client/jsonrpc_client/proxy_api_bases/lifecycle_base.py +222 -0
- mcp_proxy_adapter/client/jsonrpc_client/proxy_api_bases/register_base.py +230 -0
- mcp_proxy_adapter/client/jsonrpc_client/proxy_api_bases/uuid_base.py +95 -0
- mcp_proxy_adapter/client/jsonrpc_client/queue_api.py +302 -0
- mcp_proxy_adapter/client/jsonrpc_client/queue_status.py +192 -0
- mcp_proxy_adapter/client/jsonrpc_client/schema_generator.py +143 -0
- mcp_proxy_adapter/client/jsonrpc_client/schema_generator_bases/__init__.py +1 -0
- mcp_proxy_adapter/client/jsonrpc_client/schema_generator_bases/models.py +45 -0
- mcp_proxy_adapter/client/jsonrpc_client/schema_generator_bases/parse_base.py +215 -0
- mcp_proxy_adapter/client/jsonrpc_client/schema_generator_bases/validate_base.py +181 -0
- mcp_proxy_adapter/client/jsonrpc_client/transfer_integrity.py +57 -0
- mcp_proxy_adapter/client/jsonrpc_client/transport/__init__.py +161 -0
- mcp_proxy_adapter/client/jsonrpc_client/transport/constants.py +30 -0
- mcp_proxy_adapter/client/jsonrpc_client/transport/helpers.py +118 -0
- mcp_proxy_adapter/client/jsonrpc_client/transport/http_base.py +325 -0
- mcp_proxy_adapter/client/jsonrpc_client/transport/rpc_base.py +311 -0
- mcp_proxy_adapter/client/jsonrpc_client/transport/tls_base.py +295 -0
- mcp_proxy_adapter/client/jsonrpc_client/transport/transfer_base.py +282 -0
- mcp_proxy_adapter/client/jsonrpc_client/ws_command_session.py +230 -0
- mcp_proxy_adapter/client/jsonrpc_client/ws_command_session_bases/__init__.py +1 -0
- mcp_proxy_adapter/client/jsonrpc_client/ws_command_session_bases/core_base.py +154 -0
- mcp_proxy_adapter/client/jsonrpc_client/ws_command_session_bases/helpers.py +72 -0
- mcp_proxy_adapter/client/jsonrpc_client/ws_command_session_bases/wait_base.py +279 -0
- mcp_proxy_adapter/client/jsonrpc_client/ws_job_status.py +337 -0
- mcp_proxy_adapter/client/jsonrpc_client/ws_job_status_parts/__init__.py +1 -0
- mcp_proxy_adapter/client/jsonrpc_client/ws_job_status_parts/channel.py +159 -0
- mcp_proxy_adapter/client/jsonrpc_client/ws_job_status_parts/command_channel.py +154 -0
- mcp_proxy_adapter/client/jsonrpc_client/ws_job_status_parts/helpers.py +76 -0
- mcp_proxy_adapter/client/proxy.py +124 -0
- mcp_proxy_adapter/commands/__init__.py +27 -0
- mcp_proxy_adapter/commands/base.py +998 -0
- mcp_proxy_adapter/commands/builtin_commands.py +186 -0
- mcp_proxy_adapter/commands/command_help_info.py +101 -0
- mcp_proxy_adapter/commands/command_registry/__init__.py +55 -0
- mcp_proxy_adapter/commands/command_registry/builtins_part.py +206 -0
- mcp_proxy_adapter/commands/command_registry/facade.py +310 -0
- mcp_proxy_adapter/commands/command_registry/lifecycle_part.py +232 -0
- mcp_proxy_adapter/commands/command_registry/loader.py +145 -0
- mcp_proxy_adapter/commands/command_registry/mutations_part.py +228 -0
- mcp_proxy_adapter/commands/command_registry/part_base.py +59 -0
- mcp_proxy_adapter/commands/command_registry/queries_part.py +304 -0
- mcp_proxy_adapter/commands/config_command.py +208 -0
- mcp_proxy_adapter/commands/dependency_container.py +35 -0
- mcp_proxy_adapter/commands/echo_command.py +97 -0
- mcp_proxy_adapter/commands/health_command.py +162 -0
- mcp_proxy_adapter/commands/help_command.py +296 -0
- mcp_proxy_adapter/commands/hooks.py +590 -0
- mcp_proxy_adapter/commands/job_metadata.py +26 -0
- mcp_proxy_adapter/commands/load_command.py +134 -0
- mcp_proxy_adapter/commands/nested_validation.py +185 -0
- mcp_proxy_adapter/commands/plugins_command.py +250 -0
- mcp_proxy_adapter/commands/proxy_registration_command.py +475 -0
- mcp_proxy_adapter/commands/queue/__init__.py +83 -0
- mcp_proxy_adapter/commands/queue/add_job_command.py +358 -0
- mcp_proxy_adapter/commands/queue/command_execution_diagnostics.py +100 -0
- mcp_proxy_adapter/commands/queue/delete_job_command.py +92 -0
- mcp_proxy_adapter/commands/queue/get_logs_command.py +90 -0
- mcp_proxy_adapter/commands/queue/get_status_command.py +105 -0
- mcp_proxy_adapter/commands/queue/health_command.py +44 -0
- mcp_proxy_adapter/commands/queue/job_domain_errors.py +117 -0
- mcp_proxy_adapter/commands/queue/job_params.py +163 -0
- mcp_proxy_adapter/commands/queue/jobs/__init__.py +41 -0
- mcp_proxy_adapter/commands/queue/jobs/basic_jobs.py +205 -0
- mcp_proxy_adapter/commands/queue/jobs/command_execution_job.py +198 -0
- mcp_proxy_adapter/commands/queue/jobs/command_restore_base.py +48 -0
- mcp_proxy_adapter/commands/queue/jobs/command_run_base.py +389 -0
- mcp_proxy_adapter/commands/queue/jobs/job_helpers.py +80 -0
- mcp_proxy_adapter/commands/queue/jobs/long_jobs.py +257 -0
- mcp_proxy_adapter/commands/queue/list_jobs_command.py +127 -0
- mcp_proxy_adapter/commands/queue/start_job_command.py +97 -0
- mcp_proxy_adapter/commands/queue/stop_job_command.py +107 -0
- mcp_proxy_adapter/commands/queue_commands.py +49 -0
- mcp_proxy_adapter/commands/registration_status_command.py +83 -0
- mcp_proxy_adapter/commands/reload_command.py +183 -0
- mcp_proxy_adapter/commands/result.py +201 -0
- mcp_proxy_adapter/commands/result_helpers.py +43 -0
- mcp_proxy_adapter/commands/role_test_command.py +119 -0
- mcp_proxy_adapter/commands/roles_management_command/__init__.py +58 -0
- mcp_proxy_adapter/commands/roles_management_command/actions_part.py +400 -0
- mcp_proxy_adapter/commands/roles_management_command/dispatch_part.py +239 -0
- mcp_proxy_adapter/commands/roles_management_command/facade.py +233 -0
- mcp_proxy_adapter/commands/roles_management_command/part_base.py +61 -0
- mcp_proxy_adapter/commands/roles_management_command/results.py +105 -0
- mcp_proxy_adapter/commands/roles_management_command/storage_part.py +181 -0
- mcp_proxy_adapter/commands/schema_helpers.py +45 -0
- mcp_proxy_adapter/commands/settings_command.py +205 -0
- mcp_proxy_adapter/commands/transfer_command_support.py +83 -0
- mcp_proxy_adapter/commands/transfer_download_begin_command.py +245 -0
- mcp_proxy_adapter/commands/transfer_download_status_command.py +121 -0
- mcp_proxy_adapter/commands/transfer_schema_support.py +96 -0
- mcp_proxy_adapter/commands/transfer_upload_begin_command.py +254 -0
- mcp_proxy_adapter/commands/transfer_upload_complete_command.py +161 -0
- mcp_proxy_adapter/commands/transfer_upload_status_command.py +122 -0
- mcp_proxy_adapter/commands/transport_management_command.py +144 -0
- mcp_proxy_adapter/commands/unload_command.py +109 -0
- mcp_proxy_adapter/config.py +30 -0
- mcp_proxy_adapter/core/__init__.py +8 -0
- mcp_proxy_adapter/core/app_factory/__init__.py +17 -0
- mcp_proxy_adapter/core/app_factory/app_creator.py +66 -0
- mcp_proxy_adapter/core/app_factory/config_loader.py +125 -0
- mcp_proxy_adapter/core/app_factory/factory.py +158 -0
- mcp_proxy_adapter/core/app_factory/server_runner.py +152 -0
- mcp_proxy_adapter/core/app_factory/ssl_config.py +194 -0
- mcp_proxy_adapter/core/app_factory/validators.py +57 -0
- mcp_proxy_adapter/core/async_context.py +28 -0
- mcp_proxy_adapter/core/auth/__init__.py +18 -0
- mcp_proxy_adapter/core/auth/certificate_validator.py +239 -0
- mcp_proxy_adapter/core/auth/models.py +47 -0
- mcp_proxy_adapter/core/auth/mtls_validator.py +84 -0
- mcp_proxy_adapter/core/auth/token_validator.py +114 -0
- mcp_proxy_adapter/core/auth_validator.py +137 -0
- mcp_proxy_adapter/core/certificate/__init__.py +20 -0
- mcp_proxy_adapter/core/certificate/certificate_validator/__init__.py +55 -0
- mcp_proxy_adapter/core/certificate/certificate_validator/facade.py +340 -0
- mcp_proxy_adapter/core/certificate/certificate_validator/info_part.py +130 -0
- mcp_proxy_adapter/core/certificate/certificate_validator/key_part.py +146 -0
- mcp_proxy_adapter/core/certificate/certificate_validator/part_base.py +65 -0
- mcp_proxy_adapter/core/certificate/certificate_validator/revocation_part.py +112 -0
- mcp_proxy_adapter/core/client/__init__.py +11 -0
- mcp_proxy_adapter/core/client/auth_handler.py +120 -0
- mcp_proxy_adapter/core/client/client.py +314 -0
- mcp_proxy_adapter/core/client/factory.py +110 -0
- mcp_proxy_adapter/core/client/request_handler.py +122 -0
- mcp_proxy_adapter/core/client/ssl_handler.py +105 -0
- mcp_proxy_adapter/core/client_manager.py +281 -0
- mcp_proxy_adapter/core/client_security/__init__.py +53 -0
- mcp_proxy_adapter/core/client_security/auth_part.py +227 -0
- mcp_proxy_adapter/core/client_security/cert_part.py +124 -0
- mcp_proxy_adapter/core/client_security/facade.py +181 -0
- mcp_proxy_adapter/core/client_security/part_base.py +62 -0
- mcp_proxy_adapter/core/client_security/ssl_part.py +275 -0
- mcp_proxy_adapter/core/config/__init__.py +29 -0
- mcp_proxy_adapter/core/config/config.py +963 -0
- mcp_proxy_adapter/core/config/config_factory.py +16 -0
- mcp_proxy_adapter/core/config/config_graph.py +250 -0
- mcp_proxy_adapter/core/config/config_loader.py +70 -0
- mcp_proxy_adapter/core/config/env_placeholders.py +52 -0
- mcp_proxy_adapter/core/config/feature_manager.py +109 -0
- mcp_proxy_adapter/core/config/orchestration_section.py +119 -0
- mcp_proxy_adapter/core/config/reload_violations.py +269 -0
- mcp_proxy_adapter/core/config/section_validators.py +190 -0
- mcp_proxy_adapter/core/config/settings_declaration.py +255 -0
- mcp_proxy_adapter/core/config/simple_config.py +893 -0
- mcp_proxy_adapter/core/config/simple_config_generator.py +917 -0
- mcp_proxy_adapter/core/config/simple_config_validator.py +333 -0
- mcp_proxy_adapter/core/config/validators/__init__.py +29 -0
- mcp_proxy_adapter/core/config/validators/auth_validator.py +146 -0
- mcp_proxy_adapter/core/config/validators/base_validator.py +102 -0
- mcp_proxy_adapter/core/config/validators/certificate_validator_helper.py +114 -0
- mcp_proxy_adapter/core/config/validators/client_validator.py +131 -0
- mcp_proxy_adapter/core/config/validators/job_push_validator.py +55 -0
- mcp_proxy_adapter/core/config/validators/queue_manager_validator.py +133 -0
- mcp_proxy_adapter/core/config/validators/registration_validator.py +366 -0
- mcp_proxy_adapter/core/config/validators/server_validation_validator.py +154 -0
- mcp_proxy_adapter/core/config/validators/server_validator.py +326 -0
- mcp_proxy_adapter/core/config/validators/ssl_validator.py +221 -0
- mcp_proxy_adapter/core/config/websocket_validator.py +99 -0
- mcp_proxy_adapter/core/config_validator.py +29 -0
- mcp_proxy_adapter/core/constants.py +201 -0
- mcp_proxy_adapter/core/crl_utils.py +338 -0
- mcp_proxy_adapter/core/date_utils.py +119 -0
- mcp_proxy_adapter/core/delivery/__init__.py +35 -0
- mcp_proxy_adapter/core/delivery/contracts.py +57 -0
- mcp_proxy_adapter/core/delivery/exceptions.py +19 -0
- mcp_proxy_adapter/core/delivery/terminal_replay_store.py +129 -0
- mcp_proxy_adapter/core/delivery/ws_delivery_manager.py +117 -0
- mcp_proxy_adapter/core/domain_errors.py +189 -0
- mcp_proxy_adapter/core/error_handling.py +98 -0
- mcp_proxy_adapter/core/errors/__init__.py +259 -0
- mcp_proxy_adapter/core/errors/config_errors.py +142 -0
- mcp_proxy_adapter/core/file_utils.py +94 -0
- mcp_proxy_adapter/core/job_manager.py +115 -0
- mcp_proxy_adapter/core/job_push/__init__.py +124 -0
- mcp_proxy_adapter/core/job_push/caller_loss.py +89 -0
- mcp_proxy_adapter/core/job_push/engine.py +282 -0
- mcp_proxy_adapter/core/job_push/events/__init__.py +111 -0
- mcp_proxy_adapter/core/job_push/events/builders.py +282 -0
- mcp_proxy_adapter/core/job_push/events/command_session_payloads.py +50 -0
- mcp_proxy_adapter/core/job_push/events/delivery_payloads.py +52 -0
- mcp_proxy_adapter/core/job_push/events/event_names.py +163 -0
- mcp_proxy_adapter/core/job_push/events/job_payloads.py +83 -0
- mcp_proxy_adapter/core/job_push/events/transfer_payloads.py +72 -0
- mcp_proxy_adapter/core/job_push/execute_async_deliver_guard.py +55 -0
- mcp_proxy_adapter/core/job_push/finish_signal.py +91 -0
- mcp_proxy_adapter/core/job_push/hooks.py +53 -0
- mcp_proxy_adapter/core/job_push/job_status_accumulator.py +376 -0
- mcp_proxy_adapter/core/job_push/lifespan_wiring.py +252 -0
- mcp_proxy_adapter/core/job_push/notifier.py +139 -0
- mcp_proxy_adapter/core/job_push/notifier_policy.py +38 -0
- mcp_proxy_adapter/core/job_push/queue_custom_push.py +67 -0
- mcp_proxy_adapter/core/job_push/subscriptions.py +160 -0
- mcp_proxy_adapter/core/job_push/transfer_correlation.py +47 -0
- mcp_proxy_adapter/core/job_push/transfer_push.py +135 -0
- mcp_proxy_adapter/core/json_utils.py +81 -0
- mcp_proxy_adapter/core/logging/__init__.py +42 -0
- mcp_proxy_adapter/core/logging/formatters.py +55 -0
- mcp_proxy_adapter/core/logging/global_logger.py +41 -0
- mcp_proxy_adapter/core/logging/request_logger.py +50 -0
- mcp_proxy_adapter/core/logging/setup.py +190 -0
- mcp_proxy_adapter/core/logging/worker.py +107 -0
- mcp_proxy_adapter/core/mtls_asgi_app.py +216 -0
- mcp_proxy_adapter/core/mtls_server.py +180 -0
- mcp_proxy_adapter/core/orchestration/__init__.py +90 -0
- mcp_proxy_adapter/core/orchestration/candidate_validator.py +196 -0
- mcp_proxy_adapter/core/orchestration/catalog_builder.py +136 -0
- mcp_proxy_adapter/core/orchestration/catalog_snapshot.py +115 -0
- mcp_proxy_adapter/core/orchestration/command_record.py +43 -0
- mcp_proxy_adapter/core/orchestration/discovery_client.py +229 -0
- mcp_proxy_adapter/core/orchestration/orchestration_api.py +273 -0
- mcp_proxy_adapter/core/orchestration/orchestration_config.py +146 -0
- mcp_proxy_adapter/core/orchestration/orchestration_errors.py +305 -0
- mcp_proxy_adapter/core/orchestration/orchestration_lifespan.py +199 -0
- mcp_proxy_adapter/core/orchestration/parameter_graph.py +106 -0
- mcp_proxy_adapter/core/orchestration/polling_loop.py +281 -0
- mcp_proxy_adapter/core/orchestration/server_record.py +37 -0
- mcp_proxy_adapter/core/orchestration/snapshot_holder.py +90 -0
- mcp_proxy_adapter/core/orchestration/tool_context_exposure.py +83 -0
- mcp_proxy_adapter/core/orchestration/tool_context_snapshot.py +164 -0
- mcp_proxy_adapter/core/path_utils.py +220 -0
- mcp_proxy_adapter/core/protocol_manager.py +260 -0
- mcp_proxy_adapter/core/proxy/__init__.py +62 -0
- mcp_proxy_adapter/core/proxy/auth_manager.py +110 -0
- mcp_proxy_adapter/core/proxy_client.py +252 -0
- mcp_proxy_adapter/core/proxy_registration.py +55 -0
- mcp_proxy_adapter/core/role_utils.py +166 -0
- mcp_proxy_adapter/core/server_adapter.py +302 -0
- mcp_proxy_adapter/core/server_engine.py +384 -0
- mcp_proxy_adapter/core/settings.py +299 -0
- mcp_proxy_adapter/core/signal_handler.py +136 -0
- mcp_proxy_adapter/core/ssl_utils.py +482 -0
- mcp_proxy_adapter/core/transport_manager.py +168 -0
- mcp_proxy_adapter/core/utils.py +74 -0
- mcp_proxy_adapter/core/validation/__init__.py +21 -0
- mcp_proxy_adapter/core/validation/config_validator.py +256 -0
- mcp_proxy_adapter/core/validation/file_validator.py +229 -0
- mcp_proxy_adapter/core/validation/protocol_validator.py +322 -0
- mcp_proxy_adapter/core/validation/proxy_registration_validator.py +268 -0
- mcp_proxy_adapter/core/validation/security_validator.py +300 -0
- mcp_proxy_adapter/core/validation/validation_result.py +34 -0
- mcp_proxy_adapter/core/validation/validator_support.py +64 -0
- mcp_proxy_adapter/core/validation_utils.py +160 -0
- mcp_proxy_adapter/core/ws_timeouts.py +88 -0
- mcp_proxy_adapter/custom_openapi.py +93 -0
- mcp_proxy_adapter/examples/PROTOCOL_EXAMPLES.md +79 -0
- mcp_proxy_adapter/examples/README.md +272 -0
- mcp_proxy_adapter/examples/README_EN.md +258 -0
- mcp_proxy_adapter/examples/SECURITY_TESTING.md +455 -0
- mcp_proxy_adapter/examples/__init__.py +16 -0
- mcp_proxy_adapter/examples/basic_framework/__init__.py +9 -0
- mcp_proxy_adapter/examples/basic_framework/commands/__init__.py +4 -0
- mcp_proxy_adapter/examples/basic_framework/configs/http_auth.json +21 -0
- mcp_proxy_adapter/examples/basic_framework/configs/http_simple.json +21 -0
- mcp_proxy_adapter/examples/basic_framework/configs/https_auth.json +21 -0
- mcp_proxy_adapter/examples/basic_framework/configs/https_no_protocol_middleware.json +21 -0
- mcp_proxy_adapter/examples/basic_framework/configs/https_simple.json +21 -0
- mcp_proxy_adapter/examples/basic_framework/configs/mtls_no_protocol_middleware.json +21 -0
- mcp_proxy_adapter/examples/basic_framework/configs/mtls_no_roles.json +21 -0
- mcp_proxy_adapter/examples/basic_framework/configs/mtls_simple.json +21 -0
- mcp_proxy_adapter/examples/basic_framework/configs/mtls_with_registration.json +73 -0
- mcp_proxy_adapter/examples/basic_framework/configs/mtls_with_roles.json +21 -0
- mcp_proxy_adapter/examples/basic_framework/hooks/__init__.py +4 -0
- mcp_proxy_adapter/examples/basic_framework/main.py +123 -0
- mcp_proxy_adapter/examples/basic_framework/roles.json +1 -0
- mcp_proxy_adapter/examples/bug_report_security_framework.md +141 -0
- mcp_proxy_adapter/examples/cert_config.json +1 -0
- mcp_proxy_adapter/examples/certs/cert_config.json +1 -0
- mcp_proxy_adapter/examples/check_config.py +71 -0
- mcp_proxy_adapter/examples/check_config_split_parts/__init__.py +3 -0
- mcp_proxy_adapter/examples/check_config_split_parts/checker.py +247 -0
- mcp_proxy_adapter/examples/check_config_split_parts/cli.py +68 -0
- mcp_proxy_adapter/examples/check_config_split_parts/commands.py +102 -0
- mcp_proxy_adapter/examples/cli_config_examples/__init__.py +8 -0
- mcp_proxy_adapter/examples/cli_config_examples/examples_configs/http.json +69 -0
- mcp_proxy_adapter/examples/cli_config_examples/examples_configs/https_token_roles.json +84 -0
- mcp_proxy_adapter/examples/cli_config_examples/examples_configs/mtls_roles.json +84 -0
- mcp_proxy_adapter/examples/cli_config_examples/http_basic.py +97 -0
- mcp_proxy_adapter/examples/cli_config_examples/https_token.py +128 -0
- mcp_proxy_adapter/examples/cli_config_examples/mtls_roles.py +140 -0
- mcp_proxy_adapter/examples/client_configs/api_key_client.json +1 -0
- mcp_proxy_adapter/examples/client_configs/basic_auth_client.json +1 -0
- mcp_proxy_adapter/examples/client_configs/certificate_client.json +1 -0
- mcp_proxy_adapter/examples/client_configs/jwt_client.json +1 -0
- mcp_proxy_adapter/examples/client_configs/no_auth_client.json +1 -0
- mcp_proxy_adapter/examples/client_usage_example.py +216 -0
- mcp_proxy_adapter/examples/commands/__init__.py +5 -0
- mcp_proxy_adapter/examples/comprehensive/__init__.py +10 -0
- mcp_proxy_adapter/examples/comprehensive/run.py +906 -0
- mcp_proxy_adapter/examples/comprehensive_config.json +10 -0
- mcp_proxy_adapter/examples/config.json +10 -0
- mcp_proxy_adapter/examples/config_builder.py +272 -0
- mcp_proxy_adapter/examples/config_cli.py +340 -0
- mcp_proxy_adapter/examples/config_factory.py +325 -0
- mcp_proxy_adapter/examples/configs/full_featured.json +10 -0
- mcp_proxy_adapter/examples/configs/http_auth.json +10 -0
- mcp_proxy_adapter/examples/configs/http_simple.json +10 -0
- mcp_proxy_adapter/examples/configs/http_token.json +10 -0
- mcp_proxy_adapter/examples/configs/https_auth.json +10 -0
- mcp_proxy_adapter/examples/configs/https_simple.json +10 -0
- mcp_proxy_adapter/examples/configs/https_token.json +10 -0
- mcp_proxy_adapter/examples/configs/mtls_no_roles.json +10 -0
- mcp_proxy_adapter/examples/configs/mtls_simple.json +10 -0
- mcp_proxy_adapter/examples/configs/mtls_with_proxy.json +10 -0
- mcp_proxy_adapter/examples/configs/mtls_with_roles.json +10 -0
- mcp_proxy_adapter/examples/configs/roles.json +1 -0
- mcp_proxy_adapter/examples/create_test_configs.py +216 -0
- mcp_proxy_adapter/examples/debug_role_chain.py +192 -0
- mcp_proxy_adapter/examples/demo_client.py +339 -0
- mcp_proxy_adapter/examples/examples_correct/http_example.json +10 -0
- mcp_proxy_adapter/examples/full_application/__init__.py +11 -0
- mcp_proxy_adapter/examples/full_application/commands/__init__.py +32 -0
- mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +75 -0
- mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +101 -0
- mcp_proxy_adapter/examples/full_application/commands/embed_job_status_command.py +133 -0
- mcp_proxy_adapter/examples/full_application/commands/embed_queue_command.py +153 -0
- mcp_proxy_adapter/examples/full_application/commands/long_running_command.py +175 -0
- mcp_proxy_adapter/examples/full_application/commands/slow_start_long_task_command.py +172 -0
- mcp_proxy_adapter/examples/full_application/configs/http_basic.json +73 -0
- mcp_proxy_adapter/examples/full_application/configs/http_basic_smart_assistant_proxy3004.json +67 -0
- mcp_proxy_adapter/examples/full_application/configs/http_no_registration.json +72 -0
- mcp_proxy_adapter/examples/full_application/configs/http_token.json +69 -0
- mcp_proxy_adapter/examples/full_application/configs/http_token_roles.json +81 -0
- mcp_proxy_adapter/examples/full_application/configs/http_token_roles_smart_assistant_proxy3004.json +81 -0
- mcp_proxy_adapter/examples/full_application/configs/http_token_smart_assistant_proxy3004.json +69 -0
- mcp_proxy_adapter/examples/full_application/configs/https_basic.json +74 -0
- mcp_proxy_adapter/examples/full_application/configs/https_basic_smart_assistant_proxy3004.json +81 -0
- mcp_proxy_adapter/examples/full_application/configs/https_token.json +76 -0
- mcp_proxy_adapter/examples/full_application/configs/https_token_roles.json +88 -0
- mcp_proxy_adapter/examples/full_application/configs/https_token_roles_smart_assistant_proxy3004.json +95 -0
- mcp_proxy_adapter/examples/full_application/configs/https_token_smart_assistant_proxy3004.json +83 -0
- mcp_proxy_adapter/examples/full_application/configs/mtls_no_roles.json +78 -0
- mcp_proxy_adapter/examples/full_application/configs/mtls_no_roles_correct.json +76 -0
- mcp_proxy_adapter/examples/full_application/configs/mtls_no_roles_smart_assistant_proxy3004.json +83 -0
- mcp_proxy_adapter/examples/full_application/configs/mtls_no_security.json +77 -0
- mcp_proxy_adapter/examples/full_application/configs/mtls_with_roles.json +82 -0
- mcp_proxy_adapter/examples/full_application/configs/mtls_with_roles_correct.json +88 -0
- mcp_proxy_adapter/examples/full_application/configs/mtls_with_roles_smart_assistant_proxy3004.json +95 -0
- mcp_proxy_adapter/examples/full_application/configs/mtls_ws_repro.json +76 -0
- mcp_proxy_adapter/examples/full_application/configs/proxy_server.json +64 -0
- mcp_proxy_adapter/examples/full_application/configs/proxy_server_https.json +63 -0
- mcp_proxy_adapter/examples/full_application/configs/proxy_server_mtls.json +63 -0
- mcp_proxy_adapter/examples/full_application/example_support.py +45 -0
- mcp_proxy_adapter/examples/full_application/hooks/__init__.py +4 -0
- mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +51 -0
- mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +46 -0
- mcp_proxy_adapter/examples/full_application/main.py +95 -0
- mcp_proxy_adapter/examples/full_application/main_modules/__init__.py +1 -0
- mcp_proxy_adapter/examples/full_application/main_modules/registration.py +122 -0
- mcp_proxy_adapter/examples/full_application/main_modules/runner.py +310 -0
- mcp_proxy_adapter/examples/full_application/proxy_commands/__init__.py +113 -0
- mcp_proxy_adapter/examples/full_application/proxy_commands/_shared.py +8 -0
- mcp_proxy_adapter/examples/full_application/proxy_commands/lifecycle_commands.py +196 -0
- mcp_proxy_adapter/examples/full_application/proxy_commands/register_command.py +254 -0
- mcp_proxy_adapter/examples/full_application/proxy_commands/registry_state.py +8 -0
- mcp_proxy_adapter/examples/full_application/proxy_commands/results.py +142 -0
- mcp_proxy_adapter/examples/full_application/proxy_endpoints.py +162 -0
- mcp_proxy_adapter/examples/full_application/proxy_schemas.py +91 -0
- mcp_proxy_adapter/examples/full_application/roles.json +1 -0
- mcp_proxy_adapter/examples/full_application/test_client.py +341 -0
- mcp_proxy_adapter/examples/full_application/test_minimal_server.py +57 -0
- mcp_proxy_adapter/examples/full_application/test_queue_and_descriptions.py +283 -0
- mcp_proxy_adapter/examples/full_application/test_server.py +221 -0
- mcp_proxy_adapter/examples/full_application/test_simple_server.py +141 -0
- mcp_proxy_adapter/examples/generate_all_certificates.py +74 -0
- mcp_proxy_adapter/examples/generate_config.py +44 -0
- mcp_proxy_adapter/examples/generate_config_parts/__init__.py +3 -0
- mcp_proxy_adapter/examples/generate_config_parts/builders.py +234 -0
- mcp_proxy_adapter/examples/generate_config_parts/cli.py +260 -0
- mcp_proxy_adapter/examples/generate_config_parts/outputs.py +137 -0
- mcp_proxy_adapter/examples/generator_validator_compatibility_report.md +127 -0
- mcp_proxy_adapter/examples/http_proxy_example.json +17 -0
- mcp_proxy_adapter/examples/https_proxy_example.json +17 -0
- mcp_proxy_adapter/examples/job_tracking_demo.py +235 -0
- mcp_proxy_adapter/examples/proxy_server_support.py +384 -0
- mcp_proxy_adapter/examples/queue_demo_simple.py +37 -0
- mcp_proxy_adapter/examples/queue_demo_simple_parts/__init__.py +3 -0
- mcp_proxy_adapter/examples/queue_demo_simple_parts/_shared.py +8 -0
- mcp_proxy_adapter/examples/queue_demo_simple_parts/demo.py +213 -0
- mcp_proxy_adapter/examples/queue_demo_simple_parts/mock_commands.py +130 -0
- mcp_proxy_adapter/examples/queue_demo_simple_parts/mock_manager.py +272 -0
- mcp_proxy_adapter/examples/queue_example_support.py +36 -0
- mcp_proxy_adapter/examples/queue_fire_and_forget_example.py +370 -0
- mcp_proxy_adapter/examples/queue_server_demo.py +73 -0
- mcp_proxy_adapter/examples/queue_server_example.py +76 -0
- mcp_proxy_adapter/examples/queue_server_simple.py +251 -0
- mcp_proxy_adapter/examples/required_certificates.py +216 -0
- mcp_proxy_adapter/examples/run_example.py +119 -0
- mcp_proxy_adapter/examples/run_full_test_suite.py +674 -0
- mcp_proxy_adapter/examples/run_proxy_server.py +118 -0
- mcp_proxy_adapter/examples/run_security_tests_fixed.py +876 -0
- mcp_proxy_adapter/examples/security_test/__init__.py +18 -0
- mcp_proxy_adapter/examples/security_test/auth_manager.py +49 -0
- mcp_proxy_adapter/examples/security_test/ssl_context_manager.py +144 -0
- mcp_proxy_adapter/examples/security_test/test_client.py +218 -0
- mcp_proxy_adapter/examples/security_test/test_result.py +23 -0
- mcp_proxy_adapter/examples/security_test_client.py +103 -0
- mcp_proxy_adapter/examples/server_configs/config_basic_http.json +16 -0
- mcp_proxy_adapter/examples/server_configs/config_http_token.json +16 -0
- mcp_proxy_adapter/examples/server_configs/config_https.json +16 -0
- mcp_proxy_adapter/examples/server_configs/config_https_token.json +16 -0
- mcp_proxy_adapter/examples/server_configs/config_mtls.json +16 -0
- mcp_proxy_adapter/examples/server_configs/config_proxy_registration.json +15 -0
- mcp_proxy_adapter/examples/server_configs/config_simple.json +9 -0
- mcp_proxy_adapter/examples/server_configs/http_simple.json +14 -0
- mcp_proxy_adapter/examples/server_configs/http_token.json +14 -0
- mcp_proxy_adapter/examples/server_configs/https_simple.json +14 -0
- mcp_proxy_adapter/examples/server_configs/https_token.json +14 -0
- mcp_proxy_adapter/examples/server_configs/mtls_no_roles.json +8 -0
- mcp_proxy_adapter/examples/server_configs/mtls_test.json +8 -0
- mcp_proxy_adapter/examples/server_configs/mtls_with_roles.json +14 -0
- mcp_proxy_adapter/examples/server_configs/roles.json +1 -0
- mcp_proxy_adapter/examples/setup/__init__.py +48 -0
- mcp_proxy_adapter/examples/setup/certificate_manager.py +384 -0
- mcp_proxy_adapter/examples/setup/config_generator.py +6 -0
- mcp_proxy_adapter/examples/setup/config_validator.py +140 -0
- mcp_proxy_adapter/examples/setup/environment_setup.py +143 -0
- mcp_proxy_adapter/examples/setup/test_files_generator.py +6 -0
- mcp_proxy_adapter/examples/setup/test_runner.py +143 -0
- mcp_proxy_adapter/examples/setup_test_environment.py +233 -0
- mcp_proxy_adapter/examples/simple_http_example.json +17 -0
- mcp_proxy_adapter/examples/simple_https_example.json +17 -0
- mcp_proxy_adapter/examples/simple_protocol_test.py +167 -0
- mcp_proxy_adapter/examples/test_client/README.md +166 -0
- mcp_proxy_adapter/examples/test_client/__init__.py +7 -0
- mcp_proxy_adapter/examples/test_client/main.py +102 -0
- mcp_proxy_adapter/examples/test_client/main_split_parts/__init__.py +1 -0
- mcp_proxy_adapter/examples/test_client/main_split_parts/helpers.py +83 -0
- mcp_proxy_adapter/examples/test_client/main_split_parts/runner.py +115 -0
- mcp_proxy_adapter/examples/test_client/main_split_parts/scenarios.py +195 -0
- mcp_proxy_adapter/examples/test_config.py +183 -0
- mcp_proxy_adapter/examples/test_configs/custom_https.json +10 -0
- mcp_proxy_adapter/examples/test_configs/http_simple.json +10 -0
- mcp_proxy_adapter/examples/test_examples.py +361 -0
- mcp_proxy_adapter/examples/test_mcp_server.py +249 -0
- mcp_proxy_adapter/examples/test_protocol_examples.py +373 -0
- mcp_proxy_adapter/examples/test_proxy/README.md +70 -0
- mcp_proxy_adapter/examples/test_proxy/__init__.py +7 -0
- mcp_proxy_adapter/examples/test_proxy/main.py +106 -0
- mcp_proxy_adapter/examples/test_server/README.md +58 -0
- mcp_proxy_adapter/examples/test_server/__init__.py +7 -0
- mcp_proxy_adapter/examples/test_server/main.py +349 -0
- mcp_proxy_adapter/examples/transparent_queue_commands.py +281 -0
- mcp_proxy_adapter/examples/transparent_queue_e1_sync_call.py +102 -0
- mcp_proxy_adapter/examples/transparent_queue_e2_event_stream.py +134 -0
- mcp_proxy_adapter/examples/transparent_queue_e3_ws_timeouts.py +341 -0
- mcp_proxy_adapter/examples/transparent_queue_e4_ws_fallback.py +159 -0
- mcp_proxy_adapter/examples/transparent_queue_e5_inner_failure.py +189 -0
- mcp_proxy_adapter/examples/transparent_queue_e6_atomic_state.py +203 -0
- mcp_proxy_adapter/examples/transparent_queue_e7_caller_loss.py +63 -0
- mcp_proxy_adapter/examples/transparent_queue_e7_split2/__init__.py +3 -0
- mcp_proxy_adapter/examples/transparent_queue_e7_split2/cases.py +335 -0
- mcp_proxy_adapter/examples/transparent_queue_e7_split2/helpers.py +66 -0
- mcp_proxy_adapter/examples/transparent_queue_support.py +377 -0
- mcp_proxy_adapter/examples/unified_error_handling_example.py +127 -0
- mcp_proxy_adapter/examples/unified_error_handling_split_parts/__init__.py +3 -0
- mcp_proxy_adapter/examples/unified_error_handling_split_parts/demos.py +180 -0
- mcp_proxy_adapter/examples/unified_error_handling_split_parts/runner.py +109 -0
- mcp_proxy_adapter/examples/unified_error_handling_split_parts/support.py +79 -0
- mcp_proxy_adapter/examples/unified_error_handling_texts.py +17 -0
- mcp_proxy_adapter/examples/universal_client.py +215 -0
- mcp_proxy_adapter/examples/universal_client_split_parts/__init__.py +3 -0
- mcp_proxy_adapter/examples/universal_client_split_parts/configs.py +104 -0
- mcp_proxy_adapter/examples/universal_client_split_parts/demos.py +144 -0
- mcp_proxy_adapter/examples/update_config_certificates.py +156 -0
- mcp_proxy_adapter/examples/validate_generator_compatibility_simple.py +60 -0
- mcp_proxy_adapter/examples/websocket_examples/__init__.py +8 -0
- mcp_proxy_adapter/examples/websocket_examples/client_bidirectional_websocket.py +100 -0
- mcp_proxy_adapter/examples/websocket_examples/client_websocket_job_status.py +103 -0
- mcp_proxy_adapter/examples/websocket_examples/run_ws_test_server.py +157 -0
- mcp_proxy_adapter/examples/ws_examples/__init__.py +6 -0
- mcp_proxy_adapter/examples/ws_examples/http_basic_ws.py +68 -0
- mcp_proxy_adapter/examples/ws_examples/http_token_roles_ws.py +66 -0
- mcp_proxy_adapter/examples/ws_examples/http_token_ws.py +80 -0
- mcp_proxy_adapter/examples/ws_examples/https_basic_ws.py +61 -0
- mcp_proxy_adapter/examples/ws_examples/https_token_roles_ws.py +67 -0
- mcp_proxy_adapter/examples/ws_examples/https_token_ws.py +64 -0
- mcp_proxy_adapter/examples/ws_examples/mtls_basic_ws.py +94 -0
- mcp_proxy_adapter/examples/ws_examples/mtls_roles_ws.py +88 -0
- mcp_proxy_adapter/examples/ws_examples/ws_example_runner.py +233 -0
- mcp_proxy_adapter/integrations/__init__.py +31 -0
- mcp_proxy_adapter/integrations/queuemgr_integration/__init__.py +124 -0
- mcp_proxy_adapter/integrations/queuemgr_integration/_compat.py +60 -0
- mcp_proxy_adapter/integrations/queuemgr_integration/_health.py +299 -0
- mcp_proxy_adapter/integrations/queuemgr_integration/_limits.py +70 -0
- mcp_proxy_adapter/integrations/queuemgr_integration/_process_reap.py +232 -0
- mcp_proxy_adapter/integrations/queuemgr_integration/_result_builders.py +119 -0
- mcp_proxy_adapter/integrations/queuemgr_integration/_status_helpers.py +167 -0
- mcp_proxy_adapter/integrations/queuemgr_integration/global_manager.py +174 -0
- mcp_proxy_adapter/integrations/queuemgr_integration/job_types/__init__.py +375 -0
- mcp_proxy_adapter/integrations/queuemgr_integration/job_types/value_types.py +97 -0
- mcp_proxy_adapter/integrations/queuemgr_integration/job_types/worker_probe.py +29 -0
- mcp_proxy_adapter/integrations/queuemgr_integration/manager/__init__.py +52 -0
- mcp_proxy_adapter/integrations/queuemgr_integration/manager/fallback_base.py +240 -0
- mcp_proxy_adapter/integrations/queuemgr_integration/manager/fallback_stop_base.py +179 -0
- mcp_proxy_adapter/integrations/queuemgr_integration/manager/health_base.py +460 -0
- mcp_proxy_adapter/integrations/queuemgr_integration/manager/integration.py +189 -0
- mcp_proxy_adapter/integrations/queuemgr_integration/manager/job_start_base.py +333 -0
- mcp_proxy_adapter/integrations/queuemgr_integration/manager/job_stop_base.py +274 -0
- mcp_proxy_adapter/integrations/queuemgr_integration/manager/lifecycle_base.py +393 -0
- mcp_proxy_adapter/integrations/queuemgr_integration/manager/query_base.py +269 -0
- mcp_proxy_adapter/integrations/queuemgr_registration.py +66 -0
- mcp_proxy_adapter/integrations/queuemgr_version.py +39 -0
- mcp_proxy_adapter/main.py +385 -0
- mcp_proxy_adapter/main_ssl_paths.py +29 -0
- mcp_proxy_adapter/py.typed +0 -0
- mcp_proxy_adapter/schemas/base_schema.json +114 -0
- mcp_proxy_adapter/schemas/openapi_schema.json +269 -0
- mcp_proxy_adapter/schemas/roles.json +37 -0
- mcp_proxy_adapter/schemas/roles_schema.json +162 -0
- mcp_proxy_adapter/transfer/__init__.py +56 -0
- mcp_proxy_adapter/transfer/checksums.py +81 -0
- mcp_proxy_adapter/transfer/client_downloader/__init__.py +37 -0
- mcp_proxy_adapter/transfer/client_downloader/download_support.py +109 -0
- mcp_proxy_adapter/transfer/client_downloader/downloader.py +300 -0
- mcp_proxy_adapter/transfer/client_uploader.py +278 -0
- mcp_proxy_adapter/transfer/compression.py +127 -0
- mcp_proxy_adapter/transfer/errors.py +253 -0
- mcp_proxy_adapter/transfer/json_coerce.py +32 -0
- mcp_proxy_adapter/transfer/models.py +337 -0
- mcp_proxy_adapter/transfer/path_confinement.py +69 -0
- mcp_proxy_adapter/transfer/progress_percent.py +25 -0
- mcp_proxy_adapter/transfer/server_store.py +878 -0
- mcp_proxy_adapter/version.py +8 -0
- mcp_proxy_adapter_dev-8.11.16.dist-info/METADATA +1666 -0
- mcp_proxy_adapter_dev-8.11.16.dist-info/RECORD +644 -0
- mcp_proxy_adapter_dev-8.11.16.dist-info/WHEEL +5 -0
- mcp_proxy_adapter_dev-8.11.16.dist-info/entry_points.txt +12 -0
- 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,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
|
+
]
|