mcp-proxy-adapter 6.9.43__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 +47 -0
- mcp_proxy_adapter/__main__.py +13 -0
- mcp_proxy_adapter/api/__init__.py +0 -0
- mcp_proxy_adapter/api/app.py +66 -0
- mcp_proxy_adapter/api/core/__init__.py +18 -0
- mcp_proxy_adapter/api/core/app_factory.py +355 -0
- mcp_proxy_adapter/api/core/lifespan_manager.py +55 -0
- mcp_proxy_adapter/api/core/registration_context.py +356 -0
- mcp_proxy_adapter/api/core/registration_manager.py +266 -0
- mcp_proxy_adapter/api/core/registration_tasks.py +84 -0
- mcp_proxy_adapter/api/core/ssl_context_factory.py +88 -0
- mcp_proxy_adapter/api/handlers.py +181 -0
- mcp_proxy_adapter/api/middleware/__init__.py +21 -0
- mcp_proxy_adapter/api/middleware/base.py +54 -0
- mcp_proxy_adapter/api/middleware/command_permission_middleware.py +73 -0
- mcp_proxy_adapter/api/middleware/error_handling.py +76 -0
- mcp_proxy_adapter/api/middleware/factory.py +147 -0
- mcp_proxy_adapter/api/middleware/logging.py +31 -0
- mcp_proxy_adapter/api/middleware/performance.py +51 -0
- mcp_proxy_adapter/api/middleware/protocol_middleware.py +140 -0
- mcp_proxy_adapter/api/middleware/transport_middleware.py +87 -0
- mcp_proxy_adapter/api/middleware/unified_security.py +223 -0
- mcp_proxy_adapter/api/middleware/user_info_middleware.py +132 -0
- mcp_proxy_adapter/api/openapi/__init__.py +21 -0
- mcp_proxy_adapter/api/openapi/command_integration.py +105 -0
- mcp_proxy_adapter/api/openapi/openapi_generator.py +40 -0
- mcp_proxy_adapter/api/openapi/openapi_registry.py +62 -0
- mcp_proxy_adapter/api/openapi/schema_loader.py +116 -0
- mcp_proxy_adapter/api/schemas.py +270 -0
- mcp_proxy_adapter/api/tool_integration.py +131 -0
- mcp_proxy_adapter/api/tools.py +163 -0
- mcp_proxy_adapter/cli/__init__.py +12 -0
- mcp_proxy_adapter/cli/commands/__init__.py +15 -0
- mcp_proxy_adapter/cli/commands/client.py +100 -0
- mcp_proxy_adapter/cli/commands/config_generate.py +35 -0
- mcp_proxy_adapter/cli/commands/config_validate.py +74 -0
- mcp_proxy_adapter/cli/commands/generate.py +259 -0
- mcp_proxy_adapter/cli/commands/server.py +174 -0
- mcp_proxy_adapter/cli/commands/sets.py +128 -0
- mcp_proxy_adapter/cli/commands/testconfig.py +177 -0
- mcp_proxy_adapter/cli/examples/__init__.py +8 -0
- mcp_proxy_adapter/cli/examples/http_basic.py +82 -0
- mcp_proxy_adapter/cli/examples/https_token.py +96 -0
- mcp_proxy_adapter/cli/examples/mtls_roles.py +103 -0
- mcp_proxy_adapter/cli/main.py +63 -0
- mcp_proxy_adapter/cli/parser.py +338 -0
- mcp_proxy_adapter/cli/validators.py +231 -0
- mcp_proxy_adapter/client/jsonrpc_client/__init__.py +9 -0
- mcp_proxy_adapter/client/jsonrpc_client/client.py +42 -0
- mcp_proxy_adapter/client/jsonrpc_client/command_api.py +45 -0
- mcp_proxy_adapter/client/jsonrpc_client/proxy_api.py +224 -0
- mcp_proxy_adapter/client/jsonrpc_client/queue_api.py +60 -0
- mcp_proxy_adapter/client/jsonrpc_client/transport.py +108 -0
- mcp_proxy_adapter/client/proxy.py +123 -0
- mcp_proxy_adapter/commands/__init__.py +66 -0
- mcp_proxy_adapter/commands/auth_validation_command.py +69 -0
- mcp_proxy_adapter/commands/base.py +389 -0
- mcp_proxy_adapter/commands/builtin_commands.py +30 -0
- mcp_proxy_adapter/commands/catalog/__init__.py +20 -0
- mcp_proxy_adapter/commands/catalog/catalog_loader.py +34 -0
- mcp_proxy_adapter/commands/catalog/catalog_manager.py +122 -0
- mcp_proxy_adapter/commands/catalog/catalog_syncer.py +149 -0
- mcp_proxy_adapter/commands/catalog/command_catalog.py +43 -0
- mcp_proxy_adapter/commands/catalog/dependency_manager.py +37 -0
- mcp_proxy_adapter/commands/catalog_manager.py +97 -0
- mcp_proxy_adapter/commands/cert_monitor_command.py +552 -0
- mcp_proxy_adapter/commands/certificate_management_command.py +562 -0
- mcp_proxy_adapter/commands/command_registry.py +298 -0
- mcp_proxy_adapter/commands/config_command.py +102 -0
- mcp_proxy_adapter/commands/dependency_container.py +40 -0
- mcp_proxy_adapter/commands/dependency_manager.py +143 -0
- mcp_proxy_adapter/commands/echo_command.py +48 -0
- mcp_proxy_adapter/commands/health_command.py +142 -0
- mcp_proxy_adapter/commands/help_command.py +175 -0
- mcp_proxy_adapter/commands/hooks.py +172 -0
- mcp_proxy_adapter/commands/key_management_command.py +484 -0
- mcp_proxy_adapter/commands/load_command.py +123 -0
- mcp_proxy_adapter/commands/plugins_command.py +246 -0
- mcp_proxy_adapter/commands/protocol_management_command.py +216 -0
- mcp_proxy_adapter/commands/proxy_registration_command.py +319 -0
- mcp_proxy_adapter/commands/queue_commands.py +750 -0
- mcp_proxy_adapter/commands/registration_status_command.py +76 -0
- mcp_proxy_adapter/commands/registry/__init__.py +18 -0
- mcp_proxy_adapter/commands/registry/command_info.py +103 -0
- mcp_proxy_adapter/commands/registry/command_loader.py +207 -0
- mcp_proxy_adapter/commands/registry/command_manager.py +119 -0
- mcp_proxy_adapter/commands/registry/command_registry.py +217 -0
- mcp_proxy_adapter/commands/reload_command.py +136 -0
- mcp_proxy_adapter/commands/result.py +157 -0
- mcp_proxy_adapter/commands/role_test_command.py +99 -0
- mcp_proxy_adapter/commands/roles_management_command.py +502 -0
- mcp_proxy_adapter/commands/security_command.py +472 -0
- mcp_proxy_adapter/commands/settings_command.py +113 -0
- mcp_proxy_adapter/commands/ssl_setup_command.py +306 -0
- mcp_proxy_adapter/commands/token_management_command.py +500 -0
- mcp_proxy_adapter/commands/transport_management_command.py +129 -0
- mcp_proxy_adapter/commands/unload_command.py +92 -0
- mcp_proxy_adapter/config.py +32 -0
- mcp_proxy_adapter/core/__init__.py +8 -0
- mcp_proxy_adapter/core/app_factory.py +560 -0
- mcp_proxy_adapter/core/app_runner.py +318 -0
- mcp_proxy_adapter/core/auth_validator.py +508 -0
- mcp_proxy_adapter/core/certificate/__init__.py +20 -0
- mcp_proxy_adapter/core/certificate/certificate_creator.py +372 -0
- mcp_proxy_adapter/core/certificate/certificate_extractor.py +185 -0
- mcp_proxy_adapter/core/certificate/certificate_utils.py +249 -0
- mcp_proxy_adapter/core/certificate/certificate_validator.py +388 -0
- mcp_proxy_adapter/core/certificate/ssl_context_manager.py +65 -0
- mcp_proxy_adapter/core/certificate_utils.py +249 -0
- mcp_proxy_adapter/core/client.py +608 -0
- mcp_proxy_adapter/core/client_manager.py +271 -0
- mcp_proxy_adapter/core/client_security.py +411 -0
- mcp_proxy_adapter/core/config/__init__.py +18 -0
- mcp_proxy_adapter/core/config/config.py +237 -0
- mcp_proxy_adapter/core/config/config_factory.py +22 -0
- mcp_proxy_adapter/core/config/config_loader.py +66 -0
- mcp_proxy_adapter/core/config/feature_manager.py +31 -0
- mcp_proxy_adapter/core/config/simple_config.py +116 -0
- mcp_proxy_adapter/core/config/simple_config_generator.py +100 -0
- mcp_proxy_adapter/core/config/simple_config_validator.py +380 -0
- mcp_proxy_adapter/core/config_converter.py +252 -0
- mcp_proxy_adapter/core/config_validator.py +211 -0
- mcp_proxy_adapter/core/crl_utils.py +362 -0
- mcp_proxy_adapter/core/errors.py +276 -0
- mcp_proxy_adapter/core/job_manager.py +54 -0
- mcp_proxy_adapter/core/logging.py +250 -0
- mcp_proxy_adapter/core/mtls_asgi.py +140 -0
- mcp_proxy_adapter/core/mtls_asgi_app.py +187 -0
- mcp_proxy_adapter/core/mtls_proxy.py +229 -0
- mcp_proxy_adapter/core/mtls_server.py +154 -0
- mcp_proxy_adapter/core/protocol_manager.py +232 -0
- mcp_proxy_adapter/core/proxy/__init__.py +19 -0
- mcp_proxy_adapter/core/proxy/auth_manager.py +26 -0
- mcp_proxy_adapter/core/proxy/proxy_registration_manager.py +160 -0
- mcp_proxy_adapter/core/proxy/registration_client.py +186 -0
- mcp_proxy_adapter/core/proxy/ssl_manager.py +101 -0
- mcp_proxy_adapter/core/proxy_client.py +184 -0
- mcp_proxy_adapter/core/proxy_registration.py +80 -0
- mcp_proxy_adapter/core/role_utils.py +103 -0
- mcp_proxy_adapter/core/security_adapter.py +343 -0
- mcp_proxy_adapter/core/security_factory.py +96 -0
- mcp_proxy_adapter/core/security_integration.py +342 -0
- mcp_proxy_adapter/core/server_adapter.py +251 -0
- mcp_proxy_adapter/core/server_engine.py +217 -0
- mcp_proxy_adapter/core/settings.py +260 -0
- mcp_proxy_adapter/core/signal_handler.py +107 -0
- mcp_proxy_adapter/core/ssl_utils.py +161 -0
- mcp_proxy_adapter/core/transport_manager.py +153 -0
- mcp_proxy_adapter/core/unified_config_adapter.py +471 -0
- mcp_proxy_adapter/core/utils.py +101 -0
- mcp_proxy_adapter/core/validation/__init__.py +21 -0
- mcp_proxy_adapter/core/validation/config_validator.py +219 -0
- mcp_proxy_adapter/core/validation/file_validator.py +131 -0
- mcp_proxy_adapter/core/validation/protocol_validator.py +190 -0
- mcp_proxy_adapter/core/validation/security_validator.py +140 -0
- mcp_proxy_adapter/core/validation/validation_result.py +27 -0
- mcp_proxy_adapter/custom_openapi.py +58 -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/hooks/__init__.py +4 -0
- mcp_proxy_adapter/examples/basic_framework/main.py +52 -0
- mcp_proxy_adapter/examples/bugfix_certificate_config.py +261 -0
- mcp_proxy_adapter/examples/cert_manager_bugfix.py +203 -0
- mcp_proxy_adapter/examples/check_config.py +413 -0
- mcp_proxy_adapter/examples/client_usage_example.py +164 -0
- mcp_proxy_adapter/examples/commands/__init__.py +5 -0
- mcp_proxy_adapter/examples/config_builder.py +234 -0
- mcp_proxy_adapter/examples/config_cli.py +282 -0
- mcp_proxy_adapter/examples/create_test_configs.py +174 -0
- mcp_proxy_adapter/examples/debug_request_state.py +130 -0
- mcp_proxy_adapter/examples/debug_role_chain.py +191 -0
- mcp_proxy_adapter/examples/demo_client.py +287 -0
- mcp_proxy_adapter/examples/full_application/__init__.py +13 -0
- mcp_proxy_adapter/examples/full_application/commands/__init__.py +8 -0
- mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +45 -0
- mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +52 -0
- mcp_proxy_adapter/examples/full_application/commands/echo_command.py +32 -0
- mcp_proxy_adapter/examples/full_application/commands/help_command.py +54 -0
- mcp_proxy_adapter/examples/full_application/commands/list_command.py +57 -0
- mcp_proxy_adapter/examples/full_application/hooks/__init__.py +5 -0
- mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +29 -0
- mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +27 -0
- mcp_proxy_adapter/examples/full_application/main.py +264 -0
- mcp_proxy_adapter/examples/full_application/proxy_endpoints.py +81 -0
- mcp_proxy_adapter/examples/full_application/run_mtls.py +252 -0
- mcp_proxy_adapter/examples/full_application/run_simple.py +152 -0
- mcp_proxy_adapter/examples/full_application/test_minimal_server.py +45 -0
- mcp_proxy_adapter/examples/full_application/test_server.py +163 -0
- mcp_proxy_adapter/examples/full_application/test_simple_server.py +62 -0
- mcp_proxy_adapter/examples/generate_config.py +502 -0
- mcp_proxy_adapter/examples/proxy_registration_example.py +335 -0
- mcp_proxy_adapter/examples/queue_demo_simple.py +632 -0
- mcp_proxy_adapter/examples/queue_integration_example.py +578 -0
- mcp_proxy_adapter/examples/queue_server_demo.py +82 -0
- mcp_proxy_adapter/examples/queue_server_example.py +85 -0
- mcp_proxy_adapter/examples/queue_server_simple.py +173 -0
- mcp_proxy_adapter/examples/required_certificates.py +208 -0
- mcp_proxy_adapter/examples/run_example.py +77 -0
- mcp_proxy_adapter/examples/run_full_test_suite.py +619 -0
- mcp_proxy_adapter/examples/run_proxy_server.py +153 -0
- mcp_proxy_adapter/examples/run_security_tests_fixed.py +435 -0
- mcp_proxy_adapter/examples/security_test/__init__.py +18 -0
- mcp_proxy_adapter/examples/security_test/auth_manager.py +14 -0
- mcp_proxy_adapter/examples/security_test/ssl_context_manager.py +28 -0
- mcp_proxy_adapter/examples/security_test/test_client.py +159 -0
- mcp_proxy_adapter/examples/security_test/test_result.py +22 -0
- mcp_proxy_adapter/examples/security_test_client.py +72 -0
- mcp_proxy_adapter/examples/setup/__init__.py +24 -0
- mcp_proxy_adapter/examples/setup/certificate_manager.py +215 -0
- mcp_proxy_adapter/examples/setup/config_generator.py +12 -0
- mcp_proxy_adapter/examples/setup/config_validator.py +118 -0
- mcp_proxy_adapter/examples/setup/environment_setup.py +62 -0
- mcp_proxy_adapter/examples/setup/test_files_generator.py +10 -0
- mcp_proxy_adapter/examples/setup/test_runner.py +89 -0
- mcp_proxy_adapter/examples/setup_test_environment.py +235 -0
- mcp_proxy_adapter/examples/simple_protocol_test.py +125 -0
- mcp_proxy_adapter/examples/test_chk_hostname_automated.py +211 -0
- mcp_proxy_adapter/examples/test_config.py +205 -0
- mcp_proxy_adapter/examples/test_config_builder.py +110 -0
- mcp_proxy_adapter/examples/test_examples.py +308 -0
- mcp_proxy_adapter/examples/test_framework_complete.py +267 -0
- mcp_proxy_adapter/examples/test_mcp_server.py +187 -0
- mcp_proxy_adapter/examples/test_protocol_examples.py +337 -0
- mcp_proxy_adapter/examples/universal_client.py +674 -0
- mcp_proxy_adapter/examples/update_config_certificates.py +135 -0
- mcp_proxy_adapter/examples/validate_generator_compatibility.py +385 -0
- mcp_proxy_adapter/examples/validate_generator_compatibility_simple.py +61 -0
- mcp_proxy_adapter/integrations/__init__.py +25 -0
- mcp_proxy_adapter/integrations/queuemgr_integration.py +462 -0
- mcp_proxy_adapter/main.py +313 -0
- mcp_proxy_adapter/openapi.py +375 -0
- mcp_proxy_adapter/schemas/base_schema.json +114 -0
- mcp_proxy_adapter/schemas/openapi_schema.json +314 -0
- mcp_proxy_adapter/schemas/roles.json +37 -0
- mcp_proxy_adapter/schemas/roles_schema.json +162 -0
- mcp_proxy_adapter/version.py +5 -0
- mcp_proxy_adapter-6.9.43.dist-info/METADATA +739 -0
- mcp_proxy_adapter-6.9.43.dist-info/RECORD +242 -0
- mcp_proxy_adapter-6.9.43.dist-info/WHEEL +5 -0
- mcp_proxy_adapter-6.9.43.dist-info/entry_points.txt +12 -0
- mcp_proxy_adapter-6.9.43.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"""MCP Proxy API Service package.
|
|
2
|
+
|
|
3
|
+
This package provides a framework for creating JSON-RPC-enabled microservices.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from mcp_proxy_adapter.version import __version__
|
|
7
|
+
from mcp_proxy_adapter.api.app import create_app
|
|
8
|
+
from mcp_proxy_adapter.commands.base import Command
|
|
9
|
+
from mcp_proxy_adapter.commands.result import CommandResult, SuccessResult, ErrorResult
|
|
10
|
+
from mcp_proxy_adapter.commands.command_registry import registry
|
|
11
|
+
from mcp_proxy_adapter.core.errors import (
|
|
12
|
+
MicroserviceError,
|
|
13
|
+
CommandError,
|
|
14
|
+
ValidationError,
|
|
15
|
+
InvalidParamsError,
|
|
16
|
+
NotFoundError,
|
|
17
|
+
TimeoutError,
|
|
18
|
+
InternalError,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
# CLI module
|
|
22
|
+
# Delayed import of CLI to avoid side effects during server startup
|
|
23
|
+
# CLI can be accessed via entrypoint `mcp-proxy-adapter` or `python -m mcp_proxy_adapter`
|
|
24
|
+
try:
|
|
25
|
+
from mcp_proxy_adapter.cli import main as cli_main
|
|
26
|
+
except Exception:
|
|
27
|
+
# Avoid import errors impacting library/server usage
|
|
28
|
+
cli_main = None
|
|
29
|
+
|
|
30
|
+
# Экспортируем основные классы и функции для удобного использования
|
|
31
|
+
__all__ = [
|
|
32
|
+
"__version__",
|
|
33
|
+
"create_app",
|
|
34
|
+
"Command",
|
|
35
|
+
"CommandResult",
|
|
36
|
+
"SuccessResult",
|
|
37
|
+
"ErrorResult",
|
|
38
|
+
"registry",
|
|
39
|
+
"MicroserviceError",
|
|
40
|
+
"CommandError",
|
|
41
|
+
"ValidationError",
|
|
42
|
+
"InvalidParamsError",
|
|
43
|
+
"NotFoundError",
|
|
44
|
+
"TimeoutError",
|
|
45
|
+
"InternalError",
|
|
46
|
+
"cli_main",
|
|
47
|
+
]
|
|
File without changes
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Module for FastAPI application setup.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import Any, Dict, Optional
|
|
6
|
+
|
|
7
|
+
from fastapi import FastAPI
|
|
8
|
+
|
|
9
|
+
from .core import AppFactory, SSLContextFactory, RegistrationManager, LifespanManager
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def create_lifespan(config_path: Optional[str] = None, current_config: Optional[Dict[str, Any]] = 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(
|
|
30
|
+
app_config: Optional[Dict[str, Any]] = None
|
|
31
|
+
) -> Optional[Any]:
|
|
32
|
+
"""
|
|
33
|
+
Create SSL context based on configuration.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
app_config: Application configuration dictionary (optional)
|
|
37
|
+
|
|
38
|
+
Returns:
|
|
39
|
+
SSL context if SSL is enabled and properly configured, None otherwise
|
|
40
|
+
"""
|
|
41
|
+
ssl_factory = SSLContextFactory()
|
|
42
|
+
return ssl_factory.create_ssl_context(app_config)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def create_app(
|
|
46
|
+
title: Optional[str] = None,
|
|
47
|
+
description: Optional[str] = None,
|
|
48
|
+
version: Optional[str] = None,
|
|
49
|
+
app_config: Optional[Dict[str, Any]] = None,
|
|
50
|
+
config_path: Optional[str] = None,
|
|
51
|
+
) -> FastAPI:
|
|
52
|
+
"""
|
|
53
|
+
Creates and configures FastAPI application.
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
title: Application title (default: "MCP Proxy Adapter")
|
|
57
|
+
description: Application description (default: "JSON-RPC API for interacting with MCP Proxy")
|
|
58
|
+
version: Application version (default: "1.0.0")
|
|
59
|
+
app_config: Application configuration dictionary (optional)
|
|
60
|
+
config_path: Path to configuration file (optional)
|
|
61
|
+
|
|
62
|
+
Returns:
|
|
63
|
+
Configured FastAPI application.
|
|
64
|
+
"""
|
|
65
|
+
app_factory = AppFactory()
|
|
66
|
+
return app_factory.create_app(title, description, version, app_config, config_path)
|
|
@@ -0,0 +1,18 @@
|
|
|
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 .ssl_context_factory import SSLContextFactory
|
|
10
|
+
from .registration_manager import RegistrationManager
|
|
11
|
+
from .lifespan_manager import LifespanManager
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
"AppFactory",
|
|
15
|
+
"SSLContextFactory",
|
|
16
|
+
"RegistrationManager",
|
|
17
|
+
"LifespanManager",
|
|
18
|
+
]
|
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Author: Vasiliy Zdanovskiy
|
|
3
|
+
email: vasilyvz@gmail.com
|
|
4
|
+
|
|
5
|
+
Application factory for MCP Proxy Adapter API.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from typing import Any, Dict, List, Optional, Union
|
|
9
|
+
|
|
10
|
+
from fastapi import FastAPI, Body
|
|
11
|
+
from mcp_proxy_adapter.api.handlers import (
|
|
12
|
+
handle_json_rpc,
|
|
13
|
+
handle_batch_json_rpc,
|
|
14
|
+
get_server_health,
|
|
15
|
+
get_commands_list,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
# from mcp_proxy_adapter.api.middleware import setup_middleware
|
|
19
|
+
try:
|
|
20
|
+
from mcp_proxy_adapter.api.schemas import (
|
|
21
|
+
JsonRpcRequest,
|
|
22
|
+
JsonRpcSuccessResponse,
|
|
23
|
+
JsonRpcErrorResponse,
|
|
24
|
+
HealthResponse,
|
|
25
|
+
CommandListResponse,
|
|
26
|
+
APIToolDescription,
|
|
27
|
+
)
|
|
28
|
+
except Exception:
|
|
29
|
+
# If schemas are unavailable, define minimal type aliases to satisfy annotations
|
|
30
|
+
JsonRpcRequest = Dict[str, Any] # type: ignore
|
|
31
|
+
JsonRpcSuccessResponse = Dict[str, Any] # type: ignore
|
|
32
|
+
JsonRpcErrorResponse = Dict[str, Any] # type: ignore
|
|
33
|
+
HealthResponse = Dict[str, Any] # type: ignore
|
|
34
|
+
CommandListResponse = Dict[str, Any] # type: ignore
|
|
35
|
+
APIToolDescription = Dict[str, Any] # type: ignore
|
|
36
|
+
|
|
37
|
+
try:
|
|
38
|
+
from mcp_proxy_adapter.api.tools import get_tool_description, execute_tool
|
|
39
|
+
except Exception:
|
|
40
|
+
get_tool_description = None
|
|
41
|
+
execute_tool = None
|
|
42
|
+
from mcp_proxy_adapter.core.logging import get_global_logger
|
|
43
|
+
from mcp_proxy_adapter.custom_openapi import custom_openapi_with_fallback
|
|
44
|
+
from .ssl_context_factory import SSLContextFactory
|
|
45
|
+
from .lifespan_manager import LifespanManager
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class AppFactory:
|
|
49
|
+
"""Factory for creating FastAPI applications."""
|
|
50
|
+
|
|
51
|
+
def __init__(self):
|
|
52
|
+
"""Initialize app factory."""
|
|
53
|
+
self.logger = get_global_logger()
|
|
54
|
+
self.ssl_factory = SSLContextFactory()
|
|
55
|
+
self.lifespan_manager = LifespanManager()
|
|
56
|
+
|
|
57
|
+
def create_app(
|
|
58
|
+
self,
|
|
59
|
+
title: Optional[str] = None,
|
|
60
|
+
description: Optional[str] = None,
|
|
61
|
+
version: Optional[str] = None,
|
|
62
|
+
app_config: Optional[Dict[str, Any]] = None,
|
|
63
|
+
config_path: Optional[str] = None,
|
|
64
|
+
) -> FastAPI:
|
|
65
|
+
"""
|
|
66
|
+
Creates and configures FastAPI application.
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
title: Application title (default: "MCP Proxy Adapter")
|
|
70
|
+
description: Application description (default: "JSON-RPC API for interacting with MCP Proxy")
|
|
71
|
+
version: Application version (default: "1.0.0")
|
|
72
|
+
app_config: Application configuration dictionary (optional)
|
|
73
|
+
config_path: Path to configuration file (optional)
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
Configured FastAPI application.
|
|
77
|
+
|
|
78
|
+
Raises:
|
|
79
|
+
SystemExit: If authentication is enabled but required files are missing (security issue)
|
|
80
|
+
"""
|
|
81
|
+
# Use provided configuration or fallback to global config
|
|
82
|
+
if app_config is not None:
|
|
83
|
+
if hasattr(app_config, "get_all"):
|
|
84
|
+
current_config = app_config.get_all()
|
|
85
|
+
elif hasattr(app_config, "keys"):
|
|
86
|
+
current_config = app_config
|
|
87
|
+
else:
|
|
88
|
+
# If app_config is not a dict-like object, use it as is
|
|
89
|
+
current_config = app_config
|
|
90
|
+
else:
|
|
91
|
+
# If no app_config provided, try to get global config
|
|
92
|
+
try:
|
|
93
|
+
from mcp_proxy_adapter.config import get_config
|
|
94
|
+
|
|
95
|
+
current_config = get_config().get_all()
|
|
96
|
+
except Exception:
|
|
97
|
+
# If global config is not available, create empty config
|
|
98
|
+
current_config = {}
|
|
99
|
+
|
|
100
|
+
# Debug: Check what config is passed to create_app
|
|
101
|
+
if app_config:
|
|
102
|
+
if hasattr(app_config, "keys"):
|
|
103
|
+
print(
|
|
104
|
+
f"🔍 Debug: create_app received app_config keys: {list(app_config.keys())}"
|
|
105
|
+
)
|
|
106
|
+
# Debug SSL configuration
|
|
107
|
+
protocol = app_config.get("server", {}).get("protocol", "http")
|
|
108
|
+
verify_client = app_config.get("transport", {}).get(
|
|
109
|
+
"verify_client", False
|
|
110
|
+
)
|
|
111
|
+
ssl_enabled = protocol in ["https", "mtls"] or verify_client
|
|
112
|
+
print(f"🔍 Debug: create_app SSL config: enabled={ssl_enabled}")
|
|
113
|
+
print(f"🔍 Debug: create_app protocol: {protocol}")
|
|
114
|
+
print(f"🔍 Debug: create_app verify_client: {verify_client}")
|
|
115
|
+
else:
|
|
116
|
+
print(
|
|
117
|
+
f"🔍 Debug: create_app received app_config type: {type(app_config)}"
|
|
118
|
+
)
|
|
119
|
+
else:
|
|
120
|
+
print("🔍 Debug: create_app received no app_config, using global config")
|
|
121
|
+
|
|
122
|
+
# Security check: Validate configuration strictly at startup (fail-fast)
|
|
123
|
+
self._validate_configuration(current_config)
|
|
124
|
+
|
|
125
|
+
# Security check: Validate all authentication configurations before startup
|
|
126
|
+
self._validate_security_configuration(current_config)
|
|
127
|
+
|
|
128
|
+
# Security check: Validate certificates at startup (fail-fast)
|
|
129
|
+
self._validate_certificates(current_config)
|
|
130
|
+
|
|
131
|
+
# Set default values
|
|
132
|
+
title = title or "MCP Proxy Adapter"
|
|
133
|
+
description = description or "JSON-RPC API for interacting with MCP Proxy"
|
|
134
|
+
version = version or "1.0.0"
|
|
135
|
+
|
|
136
|
+
# Create lifespan manager
|
|
137
|
+
lifespan = self.lifespan_manager.create_lifespan(config_path, current_config)
|
|
138
|
+
|
|
139
|
+
# Create FastAPI application
|
|
140
|
+
app = FastAPI(
|
|
141
|
+
title=title,
|
|
142
|
+
description=description,
|
|
143
|
+
version=version,
|
|
144
|
+
lifespan=lifespan,
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
# Setup middleware - disabled for now
|
|
148
|
+
# setup_middleware(app, current_config)
|
|
149
|
+
|
|
150
|
+
# Setup routes
|
|
151
|
+
self._setup_routes(app)
|
|
152
|
+
|
|
153
|
+
# Setup OpenAPI
|
|
154
|
+
app.openapi = lambda: custom_openapi_with_fallback(app)
|
|
155
|
+
|
|
156
|
+
return app
|
|
157
|
+
|
|
158
|
+
def _validate_configuration(self, current_config: Dict[str, Any]) -> None:
|
|
159
|
+
"""Validate configuration at startup."""
|
|
160
|
+
try:
|
|
161
|
+
from mcp_proxy_adapter.core.validation.config_validator import (
|
|
162
|
+
ConfigValidator,
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
validator = ConfigValidator()
|
|
166
|
+
validator.config_data = current_config
|
|
167
|
+
validation_results = validator.validate_config()
|
|
168
|
+
errors = [r for r in validation_results if r.level == "error"]
|
|
169
|
+
warnings = [r for r in validation_results if r.level == "warning"]
|
|
170
|
+
|
|
171
|
+
if errors:
|
|
172
|
+
self.logger.critical(
|
|
173
|
+
"CRITICAL CONFIG ERROR: Invalid configuration at startup:"
|
|
174
|
+
)
|
|
175
|
+
for error in errors:
|
|
176
|
+
self.logger.critical(f" - {error.message}")
|
|
177
|
+
raise SystemExit(1)
|
|
178
|
+
for warning in warnings:
|
|
179
|
+
self.logger.warning(f"Config warning: {warning.message}")
|
|
180
|
+
except Exception as ex:
|
|
181
|
+
self.logger.error(f"Failed to run startup configuration validation: {ex}")
|
|
182
|
+
|
|
183
|
+
def _validate_security_configuration(self, current_config: Dict[str, Any]) -> None:
|
|
184
|
+
"""Validate security configuration at startup."""
|
|
185
|
+
security_errors = []
|
|
186
|
+
|
|
187
|
+
print(f"🔍 Debug: current_config keys: {list(current_config.keys())}")
|
|
188
|
+
if "security" in current_config:
|
|
189
|
+
print(f"🔍 Debug: security config: {current_config['security']}")
|
|
190
|
+
if "roles" in current_config:
|
|
191
|
+
print(f"🔍 Debug: roles config: {current_config['roles']}")
|
|
192
|
+
|
|
193
|
+
# Check security framework configuration only if enabled
|
|
194
|
+
security_config = current_config.get("security", {})
|
|
195
|
+
if security_config.get("enabled", False):
|
|
196
|
+
# Validate security framework configuration
|
|
197
|
+
from mcp_proxy_adapter.core.unified_config_adapter import (
|
|
198
|
+
UnifiedConfigAdapter,
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
adapter = UnifiedConfigAdapter()
|
|
202
|
+
validation_result = adapter.validate_configuration(current_config)
|
|
203
|
+
|
|
204
|
+
if not validation_result.is_valid:
|
|
205
|
+
security_errors.extend(validation_result.errors)
|
|
206
|
+
|
|
207
|
+
# Check roles configuration only if enabled
|
|
208
|
+
# Roles validation is handled by UnifiedConfigAdapter in security section validation
|
|
209
|
+
# No need for separate validation here
|
|
210
|
+
|
|
211
|
+
# Fail if there are security errors
|
|
212
|
+
if security_errors:
|
|
213
|
+
self.logger.critical(
|
|
214
|
+
"CRITICAL SECURITY ERROR: Invalid security configuration at startup:"
|
|
215
|
+
)
|
|
216
|
+
for error in security_errors:
|
|
217
|
+
self.logger.critical(f" - {error}")
|
|
218
|
+
raise SystemExit(1)
|
|
219
|
+
|
|
220
|
+
def _validate_certificates(self, current_config: Dict[str, Any]) -> None:
|
|
221
|
+
"""
|
|
222
|
+
Validate certificates at startup.
|
|
223
|
+
|
|
224
|
+
Checks:
|
|
225
|
+
- Certificate-key match
|
|
226
|
+
- Certificate expiry
|
|
227
|
+
- Certificate chain (with provided CA or system CA store)
|
|
228
|
+
|
|
229
|
+
Raises SystemExit(1) if validation fails.
|
|
230
|
+
"""
|
|
231
|
+
try:
|
|
232
|
+
from mcp_proxy_adapter.core.certificate.certificate_validator import (
|
|
233
|
+
CertificateValidator,
|
|
234
|
+
)
|
|
235
|
+
import os
|
|
236
|
+
|
|
237
|
+
certificate_errors = []
|
|
238
|
+
|
|
239
|
+
# Check if this is SimpleConfig format
|
|
240
|
+
if "server" in current_config and "proxy_client" in current_config:
|
|
241
|
+
# SimpleConfig format
|
|
242
|
+
from mcp_proxy_adapter.core.config.simple_config import (
|
|
243
|
+
SimpleConfigModel,
|
|
244
|
+
ServerConfig,
|
|
245
|
+
ProxyClientConfig,
|
|
246
|
+
AuthConfig,
|
|
247
|
+
)
|
|
248
|
+
from mcp_proxy_adapter.core.config.simple_config_validator import (
|
|
249
|
+
SimpleConfigValidator,
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
try:
|
|
253
|
+
# Try to load as SimpleConfig
|
|
254
|
+
server_config = current_config.get("server", {})
|
|
255
|
+
proxy_client_config = current_config.get("proxy_client", {})
|
|
256
|
+
auth_config = current_config.get("auth", {})
|
|
257
|
+
|
|
258
|
+
server = ServerConfig(**server_config) # type: ignore[arg-type]
|
|
259
|
+
proxy_client = ProxyClientConfig(**proxy_client_config) # type: ignore[arg-type]
|
|
260
|
+
auth = AuthConfig(**auth_config) # type: ignore[arg-type]
|
|
261
|
+
|
|
262
|
+
# Handle nested structures
|
|
263
|
+
if isinstance(proxy_client_config.get("heartbeat"), dict):
|
|
264
|
+
from mcp_proxy_adapter.core.config.simple_config import (
|
|
265
|
+
HeartbeatConfig,
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
proxy_client.heartbeat = HeartbeatConfig(
|
|
269
|
+
**proxy_client_config["heartbeat"]
|
|
270
|
+
) # type: ignore[arg-type]
|
|
271
|
+
if isinstance(proxy_client_config.get("registration"), dict):
|
|
272
|
+
from mcp_proxy_adapter.core.config.simple_config import (
|
|
273
|
+
RegistrationConfig,
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
proxy_client.registration = RegistrationConfig(
|
|
277
|
+
**proxy_client_config["registration"]
|
|
278
|
+
) # type: ignore[arg-type]
|
|
279
|
+
|
|
280
|
+
model = SimpleConfigModel(
|
|
281
|
+
server=server, proxy_client=proxy_client, auth=auth
|
|
282
|
+
)
|
|
283
|
+
validator = SimpleConfigValidator()
|
|
284
|
+
validation_errors = validator.validate(model)
|
|
285
|
+
|
|
286
|
+
if validation_errors:
|
|
287
|
+
for error in validation_errors:
|
|
288
|
+
certificate_errors.append(error.message)
|
|
289
|
+
|
|
290
|
+
except Exception as e:
|
|
291
|
+
self.logger.error(
|
|
292
|
+
f"Failed to validate as SimpleConfig format: {e}"
|
|
293
|
+
)
|
|
294
|
+
certificate_errors.append(
|
|
295
|
+
f"Configuration validation failed: {e}. Only SimpleConfig format is supported."
|
|
296
|
+
)
|
|
297
|
+
|
|
298
|
+
# Fail if there are certificate errors
|
|
299
|
+
if certificate_errors:
|
|
300
|
+
self.logger.critical(
|
|
301
|
+
"CRITICAL CERTIFICATE ERROR: Certificate validation failed at startup:"
|
|
302
|
+
)
|
|
303
|
+
for error in certificate_errors:
|
|
304
|
+
self.logger.critical(f" - {error}")
|
|
305
|
+
self.logger.critical(
|
|
306
|
+
"Server startup aborted due to certificate validation errors"
|
|
307
|
+
)
|
|
308
|
+
raise SystemExit(1)
|
|
309
|
+
|
|
310
|
+
except SystemExit:
|
|
311
|
+
raise
|
|
312
|
+
except Exception as ex:
|
|
313
|
+
self.logger.error(f"Failed to run certificate validation: {ex}")
|
|
314
|
+
# Don't fail startup if validation itself fails, but log the error
|
|
315
|
+
self.logger.warning(
|
|
316
|
+
"Certificate validation could not be completed, but server will continue to start"
|
|
317
|
+
)
|
|
318
|
+
|
|
319
|
+
def _setup_routes(self, app: FastAPI) -> None:
|
|
320
|
+
"""Setup application routes."""
|
|
321
|
+
|
|
322
|
+
@app.get("/health", response_model=HealthResponse)
|
|
323
|
+
async def health(): # type: ignore
|
|
324
|
+
return await get_server_health() # type: ignore[misc]
|
|
325
|
+
|
|
326
|
+
@app.get("/commands", response_model=CommandListResponse)
|
|
327
|
+
async def commands(): # type: ignore
|
|
328
|
+
return await get_commands_list() # type: ignore[misc]
|
|
329
|
+
|
|
330
|
+
@app.post(
|
|
331
|
+
"/api/jsonrpc",
|
|
332
|
+
response_model=Union[JsonRpcSuccessResponse, JsonRpcErrorResponse],
|
|
333
|
+
)
|
|
334
|
+
async def jsonrpc(request: JsonRpcRequest): # type: ignore
|
|
335
|
+
return await handle_json_rpc(request.dict()) # type: ignore[misc]
|
|
336
|
+
|
|
337
|
+
@app.post(
|
|
338
|
+
"/api/jsonrpc/batch",
|
|
339
|
+
response_model=List[Union[JsonRpcSuccessResponse, JsonRpcErrorResponse]],
|
|
340
|
+
)
|
|
341
|
+
async def jsonrpc_batch(requests: List[JsonRpcRequest]): # type: ignore
|
|
342
|
+
return await handle_batch_json_rpc([req.dict() for req in requests]) # type: ignore[misc]
|
|
343
|
+
|
|
344
|
+
# Optional tool endpoints if tools module is available
|
|
345
|
+
if get_tool_description and execute_tool:
|
|
346
|
+
|
|
347
|
+
@app.get("/api/tools", response_model=List[APIToolDescription])
|
|
348
|
+
async def tools(): # type: ignore
|
|
349
|
+
return await get_tool_description() # type: ignore[misc]
|
|
350
|
+
|
|
351
|
+
@app.post("/api/tools/{tool_name}")
|
|
352
|
+
async def execute_tool_endpoint(
|
|
353
|
+
tool_name: str, params: Dict[str, Any] = Body(...)
|
|
354
|
+
):
|
|
355
|
+
return await execute_tool(tool_name, params) # type: ignore[misc]
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Author: Vasiliy Zdanovskiy
|
|
3
|
+
email: vasilyvz@gmail.com
|
|
4
|
+
|
|
5
|
+
Lifespan management utilities for MCP Proxy Adapter API.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import asyncio
|
|
9
|
+
from contextlib import asynccontextmanager
|
|
10
|
+
from typing import Any, Dict, Optional
|
|
11
|
+
|
|
12
|
+
from fastapi import FastAPI
|
|
13
|
+
|
|
14
|
+
from mcp_proxy_adapter.core.logging import get_global_logger
|
|
15
|
+
from .registration_manager import RegistrationManager
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class LifespanManager:
|
|
19
|
+
"""Manager for application lifespan events."""
|
|
20
|
+
|
|
21
|
+
def __init__(self):
|
|
22
|
+
"""Initialize lifespan manager."""
|
|
23
|
+
self.logger = get_global_logger()
|
|
24
|
+
self.registration_manager = RegistrationManager()
|
|
25
|
+
|
|
26
|
+
def create_lifespan(self, config_path: Optional[str] = None, current_config: Optional[Dict[str, Any]] = None):
|
|
27
|
+
"""
|
|
28
|
+
Create lifespan manager for the FastAPI application.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
config_path: Path to configuration file (optional)
|
|
32
|
+
current_config: Current configuration data (optional)
|
|
33
|
+
|
|
34
|
+
Returns:
|
|
35
|
+
Lifespan context manager
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
@asynccontextmanager
|
|
39
|
+
async def lifespan(app: FastAPI):
|
|
40
|
+
"""Lifespan context manager."""
|
|
41
|
+
# Startup
|
|
42
|
+
get_global_logger().info("Starting MCP Proxy Adapter")
|
|
43
|
+
|
|
44
|
+
# Register with proxy if configured
|
|
45
|
+
if current_config:
|
|
46
|
+
await self.registration_manager.register_with_proxy(current_config)
|
|
47
|
+
await self.registration_manager.start_heartbeat(current_config)
|
|
48
|
+
|
|
49
|
+
yield
|
|
50
|
+
|
|
51
|
+
# Shutdown
|
|
52
|
+
get_global_logger().info("Shutting down MCP Proxy Adapter")
|
|
53
|
+
await self.registration_manager.stop()
|
|
54
|
+
|
|
55
|
+
return lifespan
|