mcp-proxy-adapter 4.1.1__py3-none-any.whl → 6.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mcp_proxy_adapter/__main__.py +32 -0
- mcp_proxy_adapter/api/app.py +290 -33
- mcp_proxy_adapter/api/handlers.py +32 -6
- mcp_proxy_adapter/api/middleware/__init__.py +38 -32
- mcp_proxy_adapter/api/middleware/command_permission_middleware.py +148 -0
- mcp_proxy_adapter/api/middleware/error_handling.py +9 -0
- mcp_proxy_adapter/api/middleware/factory.py +243 -0
- mcp_proxy_adapter/api/middleware/logging.py +32 -6
- mcp_proxy_adapter/api/middleware/protocol_middleware.py +201 -0
- mcp_proxy_adapter/api/middleware/transport_middleware.py +122 -0
- mcp_proxy_adapter/api/middleware/unified_security.py +197 -0
- mcp_proxy_adapter/api/middleware/user_info_middleware.py +158 -0
- mcp_proxy_adapter/commands/__init__.py +19 -4
- mcp_proxy_adapter/commands/auth_validation_command.py +408 -0
- mcp_proxy_adapter/commands/base.py +66 -32
- mcp_proxy_adapter/commands/builtin_commands.py +95 -0
- mcp_proxy_adapter/commands/catalog_manager.py +838 -0
- mcp_proxy_adapter/commands/cert_monitor_command.py +620 -0
- mcp_proxy_adapter/commands/certificate_management_command.py +608 -0
- mcp_proxy_adapter/commands/command_registry.py +711 -354
- mcp_proxy_adapter/commands/dependency_manager.py +245 -0
- mcp_proxy_adapter/commands/echo_command.py +81 -0
- mcp_proxy_adapter/commands/health_command.py +8 -1
- mcp_proxy_adapter/commands/help_command.py +21 -14
- mcp_proxy_adapter/commands/hooks.py +200 -167
- mcp_proxy_adapter/commands/key_management_command.py +506 -0
- mcp_proxy_adapter/commands/load_command.py +176 -0
- mcp_proxy_adapter/commands/plugins_command.py +235 -0
- mcp_proxy_adapter/commands/protocol_management_command.py +232 -0
- mcp_proxy_adapter/commands/proxy_registration_command.py +409 -0
- mcp_proxy_adapter/commands/reload_command.py +48 -50
- mcp_proxy_adapter/commands/result.py +1 -0
- mcp_proxy_adapter/commands/role_test_command.py +141 -0
- mcp_proxy_adapter/commands/roles_management_command.py +697 -0
- mcp_proxy_adapter/commands/security_command.py +488 -0
- mcp_proxy_adapter/commands/ssl_setup_command.py +366 -0
- mcp_proxy_adapter/commands/token_management_command.py +529 -0
- mcp_proxy_adapter/commands/transport_management_command.py +144 -0
- mcp_proxy_adapter/commands/unload_command.py +158 -0
- mcp_proxy_adapter/config.py +394 -14
- mcp_proxy_adapter/core/app_factory.py +410 -0
- mcp_proxy_adapter/core/app_runner.py +272 -0
- mcp_proxy_adapter/core/auth_validator.py +606 -0
- mcp_proxy_adapter/core/certificate_utils.py +1045 -0
- mcp_proxy_adapter/core/client.py +574 -0
- mcp_proxy_adapter/core/client_manager.py +284 -0
- mcp_proxy_adapter/core/client_security.py +384 -0
- mcp_proxy_adapter/core/config_converter.py +405 -0
- mcp_proxy_adapter/core/config_validator.py +218 -0
- mcp_proxy_adapter/core/logging.py +19 -3
- mcp_proxy_adapter/core/mtls_asgi.py +156 -0
- mcp_proxy_adapter/core/mtls_asgi_app.py +187 -0
- mcp_proxy_adapter/core/protocol_manager.py +385 -0
- mcp_proxy_adapter/core/proxy_client.py +602 -0
- mcp_proxy_adapter/core/proxy_registration.py +522 -0
- mcp_proxy_adapter/core/role_utils.py +426 -0
- mcp_proxy_adapter/core/security_adapter.py +370 -0
- mcp_proxy_adapter/core/security_factory.py +239 -0
- mcp_proxy_adapter/core/security_integration.py +286 -0
- mcp_proxy_adapter/core/server_adapter.py +282 -0
- mcp_proxy_adapter/core/server_engine.py +270 -0
- mcp_proxy_adapter/core/settings.py +1 -0
- mcp_proxy_adapter/core/ssl_utils.py +234 -0
- mcp_proxy_adapter/core/transport_manager.py +292 -0
- mcp_proxy_adapter/core/unified_config_adapter.py +579 -0
- mcp_proxy_adapter/custom_openapi.py +22 -11
- mcp_proxy_adapter/examples/__init__.py +13 -4
- 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 +44 -0
- mcp_proxy_adapter/examples/commands/__init__.py +5 -0
- mcp_proxy_adapter/examples/create_certificates_simple.py +550 -0
- mcp_proxy_adapter/examples/debug_request_state.py +112 -0
- mcp_proxy_adapter/examples/debug_role_chain.py +158 -0
- mcp_proxy_adapter/examples/demo_client.py +275 -0
- mcp_proxy_adapter/examples/examples/basic_framework/__init__.py +9 -0
- mcp_proxy_adapter/examples/examples/basic_framework/commands/__init__.py +4 -0
- mcp_proxy_adapter/examples/examples/basic_framework/hooks/__init__.py +4 -0
- mcp_proxy_adapter/examples/examples/basic_framework/main.py +44 -0
- mcp_proxy_adapter/examples/examples/full_application/__init__.py +12 -0
- mcp_proxy_adapter/examples/examples/full_application/commands/__init__.py +7 -0
- mcp_proxy_adapter/examples/examples/full_application/commands/custom_echo_command.py +80 -0
- mcp_proxy_adapter/examples/examples/full_application/commands/dynamic_calculator_command.py +90 -0
- mcp_proxy_adapter/examples/examples/full_application/hooks/__init__.py +7 -0
- mcp_proxy_adapter/examples/examples/full_application/hooks/application_hooks.py +75 -0
- mcp_proxy_adapter/examples/examples/full_application/hooks/builtin_command_hooks.py +71 -0
- mcp_proxy_adapter/examples/examples/full_application/main.py +173 -0
- mcp_proxy_adapter/examples/examples/full_application/proxy_endpoints.py +154 -0
- mcp_proxy_adapter/examples/full_application/__init__.py +12 -0
- mcp_proxy_adapter/examples/full_application/commands/__init__.py +7 -0
- mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +80 -0
- mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +90 -0
- mcp_proxy_adapter/examples/full_application/hooks/__init__.py +7 -0
- mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +75 -0
- mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +71 -0
- mcp_proxy_adapter/examples/full_application/main.py +173 -0
- mcp_proxy_adapter/examples/full_application/proxy_endpoints.py +154 -0
- mcp_proxy_adapter/examples/generate_all_certificates.py +362 -0
- mcp_proxy_adapter/examples/generate_certificates.py +177 -0
- mcp_proxy_adapter/examples/generate_certificates_and_tokens.py +369 -0
- mcp_proxy_adapter/examples/generate_test_configs.py +331 -0
- mcp_proxy_adapter/examples/proxy_registration_example.py +334 -0
- mcp_proxy_adapter/examples/run_example.py +59 -0
- mcp_proxy_adapter/examples/run_full_test_suite.py +318 -0
- mcp_proxy_adapter/examples/run_proxy_server.py +146 -0
- mcp_proxy_adapter/examples/run_security_tests.py +544 -0
- mcp_proxy_adapter/examples/run_security_tests_fixed.py +247 -0
- mcp_proxy_adapter/examples/scripts/config_generator.py +740 -0
- mcp_proxy_adapter/examples/scripts/create_certificates_simple.py +560 -0
- mcp_proxy_adapter/examples/scripts/generate_certificates_and_tokens.py +369 -0
- mcp_proxy_adapter/examples/security_test_client.py +782 -0
- mcp_proxy_adapter/examples/setup_test_environment.py +328 -0
- mcp_proxy_adapter/examples/test_config.py +148 -0
- mcp_proxy_adapter/examples/test_config_generator.py +86 -0
- mcp_proxy_adapter/examples/test_examples.py +281 -0
- mcp_proxy_adapter/examples/universal_client.py +620 -0
- mcp_proxy_adapter/main.py +93 -0
- mcp_proxy_adapter/utils/config_generator.py +1008 -0
- mcp_proxy_adapter/version.py +5 -2
- mcp_proxy_adapter-6.0.1.dist-info/METADATA +679 -0
- mcp_proxy_adapter-6.0.1.dist-info/RECORD +140 -0
- mcp_proxy_adapter-6.0.1.dist-info/entry_points.txt +2 -0
- {mcp_proxy_adapter-4.1.1.dist-info → mcp_proxy_adapter-6.0.1.dist-info}/licenses/LICENSE +2 -2
- mcp_proxy_adapter/api/middleware/auth.py +0 -146
- mcp_proxy_adapter/api/middleware/rate_limit.py +0 -152
- mcp_proxy_adapter/commands/reload_settings_command.py +0 -125
- mcp_proxy_adapter/examples/README.md +0 -124
- mcp_proxy_adapter/examples/basic_server/README.md +0 -60
- mcp_proxy_adapter/examples/basic_server/__init__.py +0 -7
- mcp_proxy_adapter/examples/basic_server/basic_custom_settings.json +0 -39
- mcp_proxy_adapter/examples/basic_server/config.json +0 -35
- mcp_proxy_adapter/examples/basic_server/custom_settings_example.py +0 -238
- mcp_proxy_adapter/examples/basic_server/server.py +0 -103
- mcp_proxy_adapter/examples/custom_commands/README.md +0 -127
- mcp_proxy_adapter/examples/custom_commands/__init__.py +0 -27
- mcp_proxy_adapter/examples/custom_commands/advanced_hooks.py +0 -250
- mcp_proxy_adapter/examples/custom_commands/auto_commands/__init__.py +0 -6
- mcp_proxy_adapter/examples/custom_commands/auto_commands/auto_echo_command.py +0 -103
- mcp_proxy_adapter/examples/custom_commands/auto_commands/auto_info_command.py +0 -111
- mcp_proxy_adapter/examples/custom_commands/config.json +0 -35
- mcp_proxy_adapter/examples/custom_commands/custom_health_command.py +0 -169
- mcp_proxy_adapter/examples/custom_commands/custom_help_command.py +0 -215
- mcp_proxy_adapter/examples/custom_commands/custom_openapi_generator.py +0 -76
- mcp_proxy_adapter/examples/custom_commands/custom_settings.json +0 -96
- mcp_proxy_adapter/examples/custom_commands/custom_settings_manager.py +0 -241
- mcp_proxy_adapter/examples/custom_commands/data_transform_command.py +0 -135
- mcp_proxy_adapter/examples/custom_commands/echo_command.py +0 -122
- mcp_proxy_adapter/examples/custom_commands/hooks.py +0 -230
- mcp_proxy_adapter/examples/custom_commands/intercept_command.py +0 -123
- mcp_proxy_adapter/examples/custom_commands/manual_echo_command.py +0 -103
- mcp_proxy_adapter/examples/custom_commands/server.py +0 -228
- mcp_proxy_adapter/examples/custom_commands/test_hooks.py +0 -176
- mcp_proxy_adapter/examples/deployment/README.md +0 -49
- mcp_proxy_adapter/examples/deployment/__init__.py +0 -7
- mcp_proxy_adapter/examples/deployment/config.development.json +0 -8
- mcp_proxy_adapter/examples/deployment/config.json +0 -29
- mcp_proxy_adapter/examples/deployment/config.production.json +0 -12
- mcp_proxy_adapter/examples/deployment/config.staging.json +0 -11
- mcp_proxy_adapter/examples/deployment/docker-compose.yml +0 -31
- mcp_proxy_adapter/examples/deployment/run.sh +0 -43
- mcp_proxy_adapter/examples/deployment/run_docker.sh +0 -84
- mcp_proxy_adapter/schemas/base_schema.json +0 -114
- mcp_proxy_adapter/schemas/openapi_schema.json +0 -314
- mcp_proxy_adapter/tests/__init__.py +0 -0
- mcp_proxy_adapter/tests/api/__init__.py +0 -3
- mcp_proxy_adapter/tests/api/test_cmd_endpoint.py +0 -115
- mcp_proxy_adapter/tests/api/test_custom_openapi.py +0 -617
- mcp_proxy_adapter/tests/api/test_handlers.py +0 -522
- mcp_proxy_adapter/tests/api/test_middleware.py +0 -340
- mcp_proxy_adapter/tests/api/test_schemas.py +0 -546
- mcp_proxy_adapter/tests/api/test_tool_integration.py +0 -531
- mcp_proxy_adapter/tests/commands/__init__.py +0 -3
- mcp_proxy_adapter/tests/commands/test_config_command.py +0 -211
- mcp_proxy_adapter/tests/commands/test_echo_command.py +0 -127
- mcp_proxy_adapter/tests/commands/test_help_command.py +0 -136
- mcp_proxy_adapter/tests/conftest.py +0 -131
- mcp_proxy_adapter/tests/functional/__init__.py +0 -3
- mcp_proxy_adapter/tests/functional/test_api.py +0 -253
- mcp_proxy_adapter/tests/integration/__init__.py +0 -3
- mcp_proxy_adapter/tests/integration/test_cmd_integration.py +0 -129
- mcp_proxy_adapter/tests/integration/test_integration.py +0 -255
- mcp_proxy_adapter/tests/performance/__init__.py +0 -3
- mcp_proxy_adapter/tests/performance/test_performance.py +0 -189
- mcp_proxy_adapter/tests/stubs/__init__.py +0 -10
- mcp_proxy_adapter/tests/stubs/echo_command.py +0 -104
- mcp_proxy_adapter/tests/test_api_endpoints.py +0 -271
- mcp_proxy_adapter/tests/test_api_handlers.py +0 -289
- mcp_proxy_adapter/tests/test_base_command.py +0 -123
- mcp_proxy_adapter/tests/test_batch_requests.py +0 -117
- mcp_proxy_adapter/tests/test_command_registry.py +0 -281
- mcp_proxy_adapter/tests/test_config.py +0 -127
- mcp_proxy_adapter/tests/test_utils.py +0 -65
- mcp_proxy_adapter/tests/unit/__init__.py +0 -3
- mcp_proxy_adapter/tests/unit/test_base_command.py +0 -436
- mcp_proxy_adapter/tests/unit/test_config.py +0 -217
- mcp_proxy_adapter-4.1.1.dist-info/METADATA +0 -200
- mcp_proxy_adapter-4.1.1.dist-info/RECORD +0 -110
- {mcp_proxy_adapter-4.1.1.dist-info → mcp_proxy_adapter-6.0.1.dist-info}/WHEEL +0 -0
- {mcp_proxy_adapter-4.1.1.dist-info → mcp_proxy_adapter-6.0.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,140 @@
|
|
1
|
+
mcp_proxy_adapter/__init__.py,sha256=B7m1YWyv_Wb87-Q-JqVpHQgwajnfIgDyZ_iIxzdTbBY,1021
|
2
|
+
mcp_proxy_adapter/__main__.py,sha256=-Wp1myP9DzJNB9j97mj62C8kFk5YUbCmd0e7Rnwte0A,769
|
3
|
+
mcp_proxy_adapter/config.py,sha256=ss6A-7Ef1I7iyZ-h-bzGWGwddB47642wEhN7uwnt5bk,21563
|
4
|
+
mcp_proxy_adapter/custom_openapi.py,sha256=jYUrCy8C1mShh3sjKj-JkzSMLAvxDLTvtzSJFj5HUNg,15023
|
5
|
+
mcp_proxy_adapter/main.py,sha256=9qt_pEQdq8roUc73CumfDn6jDWP_NyfdE1lCGEynv5I,2841
|
6
|
+
mcp_proxy_adapter/openapi.py,sha256=36vOEbJjGnVZR6hUhl6mHCD29HYOEFKo2bL0JdGSm-4,13952
|
7
|
+
mcp_proxy_adapter/version.py,sha256=he5ZytTjuzxFCrKQ9AxOJw6hhMuKvgK4oyLQ4ErooZQ,76
|
8
|
+
mcp_proxy_adapter/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
9
|
+
mcp_proxy_adapter/api/app.py,sha256=khl4kaI4mJ6dNbfAK7hR97Ek-eWC9NBeuXHr6GVbLoU,28911
|
10
|
+
mcp_proxy_adapter/api/handlers.py,sha256=DcZT7MVBV33q-0EJ0iFqxE0VgBkFt6d_SqoRkntwyvc,8477
|
11
|
+
mcp_proxy_adapter/api/schemas.py,sha256=xOmiSwHaapY6myEFnLu7o-LWVPM7vwmLYZXFo2c6NfE,12381
|
12
|
+
mcp_proxy_adapter/api/tool_integration.py,sha256=MrtX7vUXCGBBuZuOs3C6EF67R_U_0xMfOmlmsAz-wuE,10245
|
13
|
+
mcp_proxy_adapter/api/tools.py,sha256=rRCRN2I8Odd2biBJZKByQS15rAWf0XwLRZEHDELc7Tg,8116
|
14
|
+
mcp_proxy_adapter/api/middleware/__init__.py,sha256=2tkokajbmHLsOS_jKEgOJq-YekyIZahDWcQChMfeKdg,2146
|
15
|
+
mcp_proxy_adapter/api/middleware/base.py,sha256=aMV9YPLHkUnJECuQWYbnlEGaj6xUJFHZR_hJb0OKvu8,2282
|
16
|
+
mcp_proxy_adapter/api/middleware/command_permission_middleware.py,sha256=sSdHTZ-ZxtcV3fJmcweB3sqlQivrYO_FO0H835jnPFA,5076
|
17
|
+
mcp_proxy_adapter/api/middleware/error_handling.py,sha256=avIZTjXj1sNOT3ekKtLAYJKM7V4duX0BF9PW-j18dEY,7134
|
18
|
+
mcp_proxy_adapter/api/middleware/factory.py,sha256=yDo7f4E-YL7qQZgGApyk8HZfLYOnrpsNx-Eh3fJBikE,8404
|
19
|
+
mcp_proxy_adapter/api/middleware/logging.py,sha256=VvUUX7bN4davCzFO6GYbN1O4sgJjOspV-EBLE3xpwpc,4730
|
20
|
+
mcp_proxy_adapter/api/middleware/performance.py,sha256=dHBxTF43LEGXMKHMH3A8ybKmwAWURd_zswqq_oC4xbw,2454
|
21
|
+
mcp_proxy_adapter/api/middleware/protocol_middleware.py,sha256=iVjJrTEfKy15ZchQUo-Mu0hBg9kEP6vgzee_3PtWd6M,8115
|
22
|
+
mcp_proxy_adapter/api/middleware/transport_middleware.py,sha256=Esy2gGKpEV5RoUTilr1YKKTDc5jh5RxsomD0VXyR2pE,4396
|
23
|
+
mcp_proxy_adapter/api/middleware/unified_security.py,sha256=fDWUeIuHjYUngVnB8gVR9ES3IQSaY9VP2YPZGXATJlU,7617
|
24
|
+
mcp_proxy_adapter/api/middleware/user_info_middleware.py,sha256=CWZvwUqieNhC8_ArTvncRjFfU3RHusO-dMcUSvRv01A,6311
|
25
|
+
mcp_proxy_adapter/commands/__init__.py,sha256=r791wg4FKhWSi5rqA3vekDcGf5kr18pwF1woX-dnZKo,1525
|
26
|
+
mcp_proxy_adapter/commands/auth_validation_command.py,sha256=z612WJDVgZwaCrxdQhATwRc5i3qxH37MPuIV6SuZPn8,15083
|
27
|
+
mcp_proxy_adapter/commands/base.py,sha256=tunyrmt-LYJMQZslAZQor3KZvOrn1IYNpL5uOAnSdxc,15791
|
28
|
+
mcp_proxy_adapter/commands/builtin_commands.py,sha256=oloxk0itnY4Uy1a3ARXqHPm48RqkHxBbHqzXZ4bUGN8,3258
|
29
|
+
mcp_proxy_adapter/commands/catalog_manager.py,sha256=FVyF2Ky8DUmvFxjiem3YeC9ASFOzCZ9Lp2MsNobA1wI,34712
|
30
|
+
mcp_proxy_adapter/commands/cert_monitor_command.py,sha256=JWitmmHDeooWXt2fWLbcfAHDeHpsTL2AuBaoka7OWNE,24485
|
31
|
+
mcp_proxy_adapter/commands/certificate_management_command.py,sha256=4byTb1yCqTQCbNH_L4p_z3HithuugzI3a-H9gjiLDhg,24440
|
32
|
+
mcp_proxy_adapter/commands/command_registry.py,sha256=mPNhLnJ4L1lSyVzYXpUjeCBJkWIqEtlzpr9JcprHIf4,35260
|
33
|
+
mcp_proxy_adapter/commands/config_command.py,sha256=-Z6BGaEQTf859l56zZpHYBeZFeIVdpMYybDrd7LOPIg,3553
|
34
|
+
mcp_proxy_adapter/commands/dependency_container.py,sha256=Uz9OPRAUZN7tsVrMVgXgPQcsRD2N-e2Ixg9XarPOlnY,3410
|
35
|
+
mcp_proxy_adapter/commands/dependency_manager.py,sha256=lmY79MBkh-JRIPsYxSkdrUE9XHi4XBCbucaEMT0w6do,7683
|
36
|
+
mcp_proxy_adapter/commands/echo_command.py,sha256=R1oDNEAJSOIuODa4Nk3z4WJXhSxniNzaZtYHADlV310,2390
|
37
|
+
mcp_proxy_adapter/commands/health_command.py,sha256=cNUfvQI4MAJQK1wKfzv_snCCK-FkL-FulVSErkMA3qw,4585
|
38
|
+
mcp_proxy_adapter/commands/help_command.py,sha256=PuanwvYmVs64DhB71gaI5rBRi_ozJ6x8afr18bRpTk4,13482
|
39
|
+
mcp_proxy_adapter/commands/hooks.py,sha256=Gu5TDSgA9EBHexWMWze8wgT63i6-dMEEwG8edWbrX3U,10060
|
40
|
+
mcp_proxy_adapter/commands/key_management_command.py,sha256=qin-iYXksIXOkZEfmJpclJSOyKaz9qRinj9uVa8hkdk,19339
|
41
|
+
mcp_proxy_adapter/commands/load_command.py,sha256=2zwPOCSBck6mr5KehyyH8lPRAqYYGeUeIIJdbxMSoZk,5984
|
42
|
+
mcp_proxy_adapter/commands/plugins_command.py,sha256=Te6YQH0ukJWIHAAEJE5DmdAilpjO1QMDa_PexhfQLH0,8531
|
43
|
+
mcp_proxy_adapter/commands/protocol_management_command.py,sha256=XSrNPGagopM4SinrSmNFW12KLng7-Oc9q6NpiInJ-QI,8485
|
44
|
+
mcp_proxy_adapter/commands/proxy_registration_command.py,sha256=yqPKgpv8oPP9mn1Blo-2VRVoWUpMcMJ29stqy2Di7hk,15394
|
45
|
+
mcp_proxy_adapter/commands/reload_command.py,sha256=6yJduQlIgXhtDSH4Q8qmfR8wZW1RVC1WT1eBIpxzCNo,7507
|
46
|
+
mcp_proxy_adapter/commands/result.py,sha256=9iFyoRRZ17q3d822XTMNyqnBvWypyoyV0NiHtM2bCd4,5604
|
47
|
+
mcp_proxy_adapter/commands/role_test_command.py,sha256=Hr45vB3W8tg_GQ4FfKOEOxW10eEb-pApo2nOPjru61M,4281
|
48
|
+
mcp_proxy_adapter/commands/roles_management_command.py,sha256=JSMkW9-Hq9ncltUvBjolQdvSeTa1FY2hoU0oD2mBon4,22471
|
49
|
+
mcp_proxy_adapter/commands/security_command.py,sha256=zKTVtb8vL_DafRHtrLqC2Mhk_DjOQ-3YwhIUh8NXJfQ,18206
|
50
|
+
mcp_proxy_adapter/commands/settings_command.py,sha256=hTBrFRABJDFYwnDf2ryfqoejUe06fM4XMOoiH0Exdyo,6407
|
51
|
+
mcp_proxy_adapter/commands/ssl_setup_command.py,sha256=wCWF7VhAB21m1FF7uR7r1mG1uLu6bFkfTfpHINM7LGI,13101
|
52
|
+
mcp_proxy_adapter/commands/token_management_command.py,sha256=7sl_fRUjWMRuP7NXoLjpLTB9wEg_aZU9dp5Ji9hbThA,18147
|
53
|
+
mcp_proxy_adapter/commands/transport_management_command.py,sha256=yv2lqUqJliYGIbYW7t0HQTrt5Cu2Y02rUjVzdznLtPk,4692
|
54
|
+
mcp_proxy_adapter/commands/unload_command.py,sha256=mhRZ23sJtTwUfWkjZzH8KDRpwxUX0kdu8LbAXAURRJc,5079
|
55
|
+
mcp_proxy_adapter/core/__init__.py,sha256=Ch50cV5Nd8m-HO9rMnVModajjwDK-OdUy7hxISDFkAM,800
|
56
|
+
mcp_proxy_adapter/core/app_factory.py,sha256=Xwyz40GNOWWa7ThArweawNBY4WI4bEI3_cj251mLHCM,17797
|
57
|
+
mcp_proxy_adapter/core/app_runner.py,sha256=JPpx9rKmaHAVdFnHRl2rXycptQkTSQ13Er7Qf1KZIA4,10614
|
58
|
+
mcp_proxy_adapter/core/auth_validator.py,sha256=lJxBVkoQWSk5CNtnPYMEJSsz4FhcXK-gB5QJ_OP9jEE,20937
|
59
|
+
mcp_proxy_adapter/core/certificate_utils.py,sha256=7VOhjRcygCToYgPTUt_MgcNILdpRBRBNZSFpeS_QrfA,39541
|
60
|
+
mcp_proxy_adapter/core/client.py,sha256=YxtaHvMoqKcjWJ-2mf2FH22wUGWUZjXMEKPqxypNOPE,21340
|
61
|
+
mcp_proxy_adapter/core/client_manager.py,sha256=sKEhapMpogqb54WIWEpz2bMjrX3wvYooX-a844IfCTU,9164
|
62
|
+
mcp_proxy_adapter/core/client_security.py,sha256=8isHpvv-7H85QzI8K3Pfyr_KdvpE2xYyIT4wqWrttNU,13575
|
63
|
+
mcp_proxy_adapter/core/config_converter.py,sha256=FAA2zx-yRgqMgzg73o9Aq5CEEfodNCeaA8Yluto4wAs,16985
|
64
|
+
mcp_proxy_adapter/core/config_validator.py,sha256=qDVmkRatuDeWylIPLjMq02Vpzff6DDTE_CstpzqGi7o,7773
|
65
|
+
mcp_proxy_adapter/core/errors.py,sha256=s34OxiIR4NCJu_pYSigKXqrIvRjUUK2OWw0X4dpDjIA,5151
|
66
|
+
mcp_proxy_adapter/core/logging.py,sha256=jQlFz52Xwapef6UD4p0acmaGFumD9XuexwW4frDN_ZM,9626
|
67
|
+
mcp_proxy_adapter/core/mtls_asgi.py,sha256=X2lAj3wk3L85amRCp_-10sqvZa5wJf_diXhwrrQReSo,5311
|
68
|
+
mcp_proxy_adapter/core/mtls_asgi_app.py,sha256=VeolP08TTaqYU5fGeaZexj6EBWBDugoVrEGXzJW4PuM,6406
|
69
|
+
mcp_proxy_adapter/core/protocol_manager.py,sha256=ISFRXjUuK4Q3uMbVB8-O_ozQSsDEH0PQA_HAKGeUrrw,14763
|
70
|
+
mcp_proxy_adapter/core/proxy_client.py,sha256=shP373Yelz7Fja22U6XnH0kT9XtPtWEFwOFlYFO97gw,22511
|
71
|
+
mcp_proxy_adapter/core/proxy_registration.py,sha256=87ko1vw61nHJGo0-xrObXiyQhrYK2K6nKr8rXID-j8c,19424
|
72
|
+
mcp_proxy_adapter/core/role_utils.py,sha256=wMoTVz3gF5fM7jozNMwsEwPkp1tui26M-t_KH1Oz8gs,12880
|
73
|
+
mcp_proxy_adapter/core/security_adapter.py,sha256=wZ3OH1WzhUdpN8N8CrGJSFFVNi474DqdazIqQ1T8PN4,13343
|
74
|
+
mcp_proxy_adapter/core/security_factory.py,sha256=4r7qvBq30XfosGD_b1ZHyNVLN8rOQ3NAKuaCOCEK8jA,8262
|
75
|
+
mcp_proxy_adapter/core/security_integration.py,sha256=6oJKVCL1CRnk3sTWX-PBzDjv737oe4QL-9r3l89kRkc,13715
|
76
|
+
mcp_proxy_adapter/core/server_adapter.py,sha256=8dhUlLxuYjaoNgMHieFCFgDRjxskP--Y5uoAhbN6RLw,9823
|
77
|
+
mcp_proxy_adapter/core/server_engine.py,sha256=SFENSDrVMlBD--HgKSRVklhrtLKSRSZhs_3UHxFCGbg,9540
|
78
|
+
mcp_proxy_adapter/core/settings.py,sha256=ZfUnmqD1tjAuaQo2VAF8evC1oHUit7gTu4WkTF0IMYI,10628
|
79
|
+
mcp_proxy_adapter/core/ssl_utils.py,sha256=_2mhpuoiRpSbUBifnQvtuziQfBRrXQUKtB58ALWTaqU,8220
|
80
|
+
mcp_proxy_adapter/core/transport_manager.py,sha256=ppcgjO-7Ulrk1ovlzlXVM89Iw4VOGA3awKgLf7FFAJ0,9518
|
81
|
+
mcp_proxy_adapter/core/unified_config_adapter.py,sha256=cpN_VrliIFGDH3JsfRkTlFdQvLcmuMYYedq0QEzlb0Y,22857
|
82
|
+
mcp_proxy_adapter/core/utils.py,sha256=ly8Ttg2v1OBukThJLxudRvmttU1hxJFLJUfat4b2dOI,3268
|
83
|
+
mcp_proxy_adapter/examples/__init__.py,sha256=k1F-EotAFbJ3JvK_rNgiH4bUztmxIWtYn0AfbAZ1ZGs,450
|
84
|
+
mcp_proxy_adapter/examples/create_certificates_simple.py,sha256=KhP-J98e3GRfEsueEtPlACyOVNWVVxRwBZWBMged_YA,25743
|
85
|
+
mcp_proxy_adapter/examples/debug_request_state.py,sha256=x_H3NIlkmIS6lZimvEM6kCXxGdpgFw99Sdui8qa_qeU,4347
|
86
|
+
mcp_proxy_adapter/examples/debug_role_chain.py,sha256=33l2Tk5mrcnwPFwqm2NTHcrWaJrXUU2wxW2I6Y4uIg4,8344
|
87
|
+
mcp_proxy_adapter/examples/demo_client.py,sha256=inic-FP5qG8oQXUaCrtEhmhac_PDZ1pcxp-M1cxSzwA,10240
|
88
|
+
mcp_proxy_adapter/examples/generate_all_certificates.py,sha256=rgcwqIkQ1eDfEIRFRXGIOz-jOSS1w0GPBRhYvMl6Vjc,16948
|
89
|
+
mcp_proxy_adapter/examples/generate_certificates.py,sha256=A34OHUEiFvINOHrm3_JiDSbp-WG-eQXIvKCsE8JAeXQ,6616
|
90
|
+
mcp_proxy_adapter/examples/generate_certificates_and_tokens.py,sha256=J0qHm_BMY8RYqfuwf7V7xKsHcsRJx8E7x-8JxmW5sPw,15988
|
91
|
+
mcp_proxy_adapter/examples/generate_test_configs.py,sha256=NLhPrA9AfPlQ0WCbOJ1B_V9OC445tanKTmq7aAWKULU,13672
|
92
|
+
mcp_proxy_adapter/examples/proxy_registration_example.py,sha256=g59_QG2D1CCqhIXEvgy2XmgXI3toLmLyH7hL3uHZwC8,12647
|
93
|
+
mcp_proxy_adapter/examples/run_example.py,sha256=o8rcy9Xo0UuZG4MpKdex3pFWYdtAi6uW8dEBQE6Yzbw,2539
|
94
|
+
mcp_proxy_adapter/examples/run_full_test_suite.py,sha256=7Z6qDOvbndGPue1P9v-GcYZxy_XPqoC9voJ7tR8eKQ8,12428
|
95
|
+
mcp_proxy_adapter/examples/run_proxy_server.py,sha256=vkEjqREcOSw2elH_VOBLa0cFjL8gCZp9nkRa8YLsndI,5119
|
96
|
+
mcp_proxy_adapter/examples/run_security_tests.py,sha256=BFeafoRXOhorJ8ScjjnlmPdRaCG8AaPAxb-PRnSGJTM,22639
|
97
|
+
mcp_proxy_adapter/examples/run_security_tests_fixed.py,sha256=fNQsbALf9548xJ0OGPKYx5Crzg1GbcL8CSh1x_oKu_A,10540
|
98
|
+
mcp_proxy_adapter/examples/security_test_client.py,sha256=0j0-RGg9kppt_IAuYeT8cbXr3N5gqBdzEyPd3RW0bs8,35558
|
99
|
+
mcp_proxy_adapter/examples/setup_test_environment.py,sha256=fAfz1U7qERY-Z9ly15Wld8Zci-5_e9zSrvYJ56Rjowo,11839
|
100
|
+
mcp_proxy_adapter/examples/test_config.py,sha256=1X9X8lNlWOcM1ZbIzteeMvLdgxnJEK_ev1BYTZiA9ws,6451
|
101
|
+
mcp_proxy_adapter/examples/test_config_generator.py,sha256=SBKL0bv-kUwUUbwrFVbxuA_6pDvK2573Jxm9wPiyI8s,3927
|
102
|
+
mcp_proxy_adapter/examples/test_examples.py,sha256=KH095FFEQDMKYZglclr5qy3cW__t3H8VX1l8dvCkQos,12132
|
103
|
+
mcp_proxy_adapter/examples/universal_client.py,sha256=IIKGRa0__KoWVla3VnVl-RjkkG_nPpM8vglPm70pV9c,26948
|
104
|
+
mcp_proxy_adapter/examples/basic_framework/__init__.py,sha256=4aYD--R6hy9n9CUxj7Osb9HcdVUMJ6_cfpu4ujkbCwI,345
|
105
|
+
mcp_proxy_adapter/examples/basic_framework/main.py,sha256=cDmqeUN1lDBBwuwLjmnP3qIyofCZ3Jr5Ct7Im-qCsUU,1728
|
106
|
+
mcp_proxy_adapter/examples/basic_framework/commands/__init__.py,sha256=_VQNLUEdsxUG-4yt9BZI_vtOxHAdGG0OUSsP6Wj-Vz4,76
|
107
|
+
mcp_proxy_adapter/examples/basic_framework/hooks/__init__.py,sha256=IE_EIXMnkdXuakZn7wLD9kBFyfDF5lYi56ejgiBeb-A,70
|
108
|
+
mcp_proxy_adapter/examples/commands/__init__.py,sha256=46FZSOABSeKPffw91JqIWL_UQD_RLL3nAR-ufgb2hr8,169
|
109
|
+
mcp_proxy_adapter/examples/examples/basic_framework/__init__.py,sha256=4aYD--R6hy9n9CUxj7Osb9HcdVUMJ6_cfpu4ujkbCwI,345
|
110
|
+
mcp_proxy_adapter/examples/examples/basic_framework/main.py,sha256=cDmqeUN1lDBBwuwLjmnP3qIyofCZ3Jr5Ct7Im-qCsUU,1728
|
111
|
+
mcp_proxy_adapter/examples/examples/basic_framework/commands/__init__.py,sha256=_VQNLUEdsxUG-4yt9BZI_vtOxHAdGG0OUSsP6Wj-Vz4,76
|
112
|
+
mcp_proxy_adapter/examples/examples/basic_framework/hooks/__init__.py,sha256=IE_EIXMnkdXuakZn7wLD9kBFyfDF5lYi56ejgiBeb-A,70
|
113
|
+
mcp_proxy_adapter/examples/examples/full_application/__init__.py,sha256=AEqN_gEBzj-swBtTOvRUWqKSdXqJVk1aUtfPghVL-2o,319
|
114
|
+
mcp_proxy_adapter/examples/examples/full_application/main.py,sha256=h2d90G6XMJFbJpo2ht7M1IqITZ9nZPi9QtH6ETeE9DI,7791
|
115
|
+
mcp_proxy_adapter/examples/examples/full_application/proxy_endpoints.py,sha256=-cpb0nIjzp6OltFHoZqrtFvb4wJf1dgT4WvQ2dcY6Bo,6045
|
116
|
+
mcp_proxy_adapter/examples/examples/full_application/commands/__init__.py,sha256=yQHxVSFkAyFLUOdk42QOebUODPlQV9IbydPgF3UKsGM,217
|
117
|
+
mcp_proxy_adapter/examples/examples/full_application/commands/custom_echo_command.py,sha256=u9_XOkoHkiFC-tn9B-yGUXfQi9OL0EDxlVVKSERI1wA,3099
|
118
|
+
mcp_proxy_adapter/examples/examples/full_application/commands/dynamic_calculator_command.py,sha256=fRWtegpUUVt4wWOz3yE3spMG4h1DM_xbSxg_WqlnbF0,3491
|
119
|
+
mcp_proxy_adapter/examples/examples/full_application/hooks/__init__.py,sha256=ORG4cL8cSXEMmZ0CEPz75OVuwg54pdDm2GIBpP4dtcs,200
|
120
|
+
mcp_proxy_adapter/examples/examples/full_application/hooks/application_hooks.py,sha256=TYXuHI-KW_mH5r8mSKgNMJCr3moeEKrqC4Eex0U298k,3457
|
121
|
+
mcp_proxy_adapter/examples/examples/full_application/hooks/builtin_command_hooks.py,sha256=IaskSrckZS6bE3aGxSBL8aTj-iJTSI2ysfsFjhjncyM,2975
|
122
|
+
mcp_proxy_adapter/examples/full_application/__init__.py,sha256=AEqN_gEBzj-swBtTOvRUWqKSdXqJVk1aUtfPghVL-2o,319
|
123
|
+
mcp_proxy_adapter/examples/full_application/main.py,sha256=h2d90G6XMJFbJpo2ht7M1IqITZ9nZPi9QtH6ETeE9DI,7791
|
124
|
+
mcp_proxy_adapter/examples/full_application/proxy_endpoints.py,sha256=-cpb0nIjzp6OltFHoZqrtFvb4wJf1dgT4WvQ2dcY6Bo,6045
|
125
|
+
mcp_proxy_adapter/examples/full_application/commands/__init__.py,sha256=yQHxVSFkAyFLUOdk42QOebUODPlQV9IbydPgF3UKsGM,217
|
126
|
+
mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py,sha256=u9_XOkoHkiFC-tn9B-yGUXfQi9OL0EDxlVVKSERI1wA,3099
|
127
|
+
mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py,sha256=fRWtegpUUVt4wWOz3yE3spMG4h1DM_xbSxg_WqlnbF0,3491
|
128
|
+
mcp_proxy_adapter/examples/full_application/hooks/__init__.py,sha256=ORG4cL8cSXEMmZ0CEPz75OVuwg54pdDm2GIBpP4dtcs,200
|
129
|
+
mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py,sha256=TYXuHI-KW_mH5r8mSKgNMJCr3moeEKrqC4Eex0U298k,3457
|
130
|
+
mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py,sha256=IaskSrckZS6bE3aGxSBL8aTj-iJTSI2ysfsFjhjncyM,2975
|
131
|
+
mcp_proxy_adapter/examples/scripts/config_generator.py,sha256=4qruYxQ2kGLVOukLX2JOW5kslJ06RhkNqTobAgh4rfw,32801
|
132
|
+
mcp_proxy_adapter/examples/scripts/create_certificates_simple.py,sha256=xkIvUYl6hbKlWImQmenG0k_CvIsOsc9ZHICiKY3rtI8,26380
|
133
|
+
mcp_proxy_adapter/examples/scripts/generate_certificates_and_tokens.py,sha256=J0qHm_BMY8RYqfuwf7V7xKsHcsRJx8E7x-8JxmW5sPw,15988
|
134
|
+
mcp_proxy_adapter/utils/config_generator.py,sha256=2dxwBh9k_nUw9kgytZso5TNOQpBqd3c-RpKSTLoHlLE,46465
|
135
|
+
mcp_proxy_adapter-6.0.1.dist-info/licenses/LICENSE,sha256=6KdtUcTwmTRbJrAmYjVn7e6S-V42ubeDJ-AiVEzZ510,1075
|
136
|
+
mcp_proxy_adapter-6.0.1.dist-info/METADATA,sha256=UYIC4jHUJrNCj-7FlIHqekZvym3C5njJhaPp8XesdXA,22347
|
137
|
+
mcp_proxy_adapter-6.0.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
138
|
+
mcp_proxy_adapter-6.0.1.dist-info/entry_points.txt,sha256=J3eV6ID0lt_VSp4lIdIgBFTqLCThgObNNxRCbyfiMHw,70
|
139
|
+
mcp_proxy_adapter-6.0.1.dist-info/top_level.txt,sha256=JZT7vPLBYrtroX-ij68JBhJYbjDdghcV-DFySRy-Nnw,18
|
140
|
+
mcp_proxy_adapter-6.0.1.dist-info/RECORD,,
|
@@ -1,6 +1,6 @@
|
|
1
1
|
MIT License
|
2
2
|
|
3
|
-
Copyright (c)
|
3
|
+
Copyright (c) 2024 Vasiliy Zdanovskiy
|
4
4
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
@@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
18
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
19
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
20
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
-
SOFTWARE.
|
21
|
+
SOFTWARE.
|
@@ -1,146 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Middleware for authentication.
|
3
|
-
"""
|
4
|
-
|
5
|
-
import json
|
6
|
-
from typing import Dict, List, Optional, Callable, Awaitable
|
7
|
-
|
8
|
-
from fastapi import Request, Response
|
9
|
-
from starlette.responses import JSONResponse
|
10
|
-
|
11
|
-
from mcp_proxy_adapter.core.logging import logger
|
12
|
-
from .base import BaseMiddleware
|
13
|
-
|
14
|
-
class AuthMiddleware(BaseMiddleware):
|
15
|
-
"""
|
16
|
-
Middleware for authenticating requests.
|
17
|
-
"""
|
18
|
-
|
19
|
-
def __init__(self, app, api_keys: Dict[str, str] = None, public_paths: List[str] = None, auth_enabled: bool = True):
|
20
|
-
"""
|
21
|
-
Initializes middleware for authentication.
|
22
|
-
|
23
|
-
Args:
|
24
|
-
app: FastAPI application
|
25
|
-
api_keys: Dictionary with API keys (key: username)
|
26
|
-
public_paths: List of paths accessible without authentication
|
27
|
-
auth_enabled: Flag to enable/disable authentication
|
28
|
-
"""
|
29
|
-
super().__init__(app)
|
30
|
-
self.api_keys = api_keys or {}
|
31
|
-
self.public_paths = public_paths or [
|
32
|
-
"/docs",
|
33
|
-
"/redoc",
|
34
|
-
"/openapi.json",
|
35
|
-
"/health"
|
36
|
-
]
|
37
|
-
self.auth_enabled = auth_enabled
|
38
|
-
|
39
|
-
async def dispatch(self, request: Request, call_next: Callable[[Request], Awaitable[Response]]) -> Response:
|
40
|
-
"""
|
41
|
-
Processes request and checks authentication.
|
42
|
-
|
43
|
-
Args:
|
44
|
-
request: Request.
|
45
|
-
call_next: Next handler.
|
46
|
-
|
47
|
-
Returns:
|
48
|
-
Response.
|
49
|
-
"""
|
50
|
-
# Check if authentication is disabled
|
51
|
-
if not self.auth_enabled:
|
52
|
-
logger.debug("Authentication is disabled, skipping authentication check")
|
53
|
-
return await call_next(request)
|
54
|
-
|
55
|
-
# Check if path is public
|
56
|
-
path = request.url.path
|
57
|
-
if self._is_public_path(path):
|
58
|
-
# If path is public, skip authentication
|
59
|
-
return await call_next(request)
|
60
|
-
|
61
|
-
# Check for API key in header
|
62
|
-
api_key = request.headers.get("X-API-Key")
|
63
|
-
|
64
|
-
if not api_key:
|
65
|
-
# Check for API key in query parameters
|
66
|
-
api_key = request.query_params.get("api_key")
|
67
|
-
|
68
|
-
if not api_key and request.method in ["POST", "PUT", "PATCH"]:
|
69
|
-
# Check for API key in JSON-RPC request body
|
70
|
-
try:
|
71
|
-
body = await request.body()
|
72
|
-
if body:
|
73
|
-
try:
|
74
|
-
body_json = json.loads(body.decode("utf-8"))
|
75
|
-
# Look for API key in params of JSON-RPC object
|
76
|
-
if isinstance(body_json, dict) and "params" in body_json:
|
77
|
-
api_key = body_json.get("params", {}).get("api_key")
|
78
|
-
except json.JSONDecodeError:
|
79
|
-
pass
|
80
|
-
except Exception:
|
81
|
-
pass
|
82
|
-
|
83
|
-
# If API key not found, return error
|
84
|
-
if not api_key:
|
85
|
-
logger.warning(f"Authentication failed: API key not provided | Path: {path}")
|
86
|
-
return self._create_error_response("API key not provided", 401)
|
87
|
-
|
88
|
-
# Check if API key is valid
|
89
|
-
username = self._validate_api_key(api_key)
|
90
|
-
if not username:
|
91
|
-
logger.warning(f"Authentication failed: Invalid API key | Path: {path}")
|
92
|
-
return self._create_error_response("Invalid API key", 401)
|
93
|
-
|
94
|
-
# If API key is valid, save user information in request state
|
95
|
-
request.state.username = username
|
96
|
-
logger.info(f"Authentication successful: {username} | Path: {path}")
|
97
|
-
|
98
|
-
# Call the next middleware or main handler
|
99
|
-
return await call_next(request)
|
100
|
-
|
101
|
-
def _is_public_path(self, path: str) -> bool:
|
102
|
-
"""
|
103
|
-
Checks if the path is public.
|
104
|
-
|
105
|
-
Args:
|
106
|
-
path: Path to check.
|
107
|
-
|
108
|
-
Returns:
|
109
|
-
True if path is public, False otherwise.
|
110
|
-
"""
|
111
|
-
return any(path.startswith(public_path) for public_path in self.public_paths)
|
112
|
-
|
113
|
-
def _validate_api_key(self, api_key: str) -> Optional[str]:
|
114
|
-
"""
|
115
|
-
Validates API key.
|
116
|
-
|
117
|
-
Args:
|
118
|
-
api_key: API key to validate.
|
119
|
-
|
120
|
-
Returns:
|
121
|
-
Username if API key is valid, otherwise None.
|
122
|
-
"""
|
123
|
-
return self.api_keys.get(api_key)
|
124
|
-
|
125
|
-
def _create_error_response(self, message: str, status_code: int) -> Response:
|
126
|
-
"""
|
127
|
-
Creates error response in JSON-RPC format.
|
128
|
-
|
129
|
-
Args:
|
130
|
-
message: Error message.
|
131
|
-
status_code: HTTP status code.
|
132
|
-
|
133
|
-
Returns:
|
134
|
-
JSON response with error.
|
135
|
-
"""
|
136
|
-
return JSONResponse(
|
137
|
-
status_code=status_code,
|
138
|
-
content={
|
139
|
-
"jsonrpc": "2.0",
|
140
|
-
"error": {
|
141
|
-
"code": -32000,
|
142
|
-
"message": message
|
143
|
-
},
|
144
|
-
"id": None
|
145
|
-
}
|
146
|
-
)
|
@@ -1,152 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Middleware for rate limiting.
|
3
|
-
"""
|
4
|
-
|
5
|
-
import time
|
6
|
-
from typing import Dict, List, Callable, Awaitable
|
7
|
-
from collections import defaultdict
|
8
|
-
|
9
|
-
from fastapi import Request, Response
|
10
|
-
from starlette.responses import JSONResponse
|
11
|
-
|
12
|
-
from mcp_proxy_adapter.core.logging import logger
|
13
|
-
from .base import BaseMiddleware
|
14
|
-
|
15
|
-
class RateLimitMiddleware(BaseMiddleware):
|
16
|
-
"""
|
17
|
-
Middleware for limiting request rate.
|
18
|
-
"""
|
19
|
-
|
20
|
-
def __init__(self, app, rate_limit: int = 100, time_window: int = 60,
|
21
|
-
by_ip: bool = True, by_user: bool = True,
|
22
|
-
public_paths: List[str] = None):
|
23
|
-
"""
|
24
|
-
Initializes middleware for rate limiting.
|
25
|
-
|
26
|
-
Args:
|
27
|
-
app: FastAPI application
|
28
|
-
rate_limit: Maximum number of requests in the specified time period
|
29
|
-
time_window: Time period in seconds
|
30
|
-
by_ip: Limit requests by IP address
|
31
|
-
by_user: Limit requests by user
|
32
|
-
public_paths: List of paths for which rate limiting is not applied
|
33
|
-
"""
|
34
|
-
super().__init__(app)
|
35
|
-
self.rate_limit = rate_limit
|
36
|
-
self.time_window = time_window
|
37
|
-
self.by_ip = by_ip
|
38
|
-
self.by_user = by_user
|
39
|
-
self.public_paths = public_paths or [
|
40
|
-
"/docs",
|
41
|
-
"/redoc",
|
42
|
-
"/openapi.json",
|
43
|
-
"/health"
|
44
|
-
]
|
45
|
-
|
46
|
-
# Storage for requests by IP
|
47
|
-
self.ip_requests = defaultdict(list)
|
48
|
-
|
49
|
-
# Storage for requests by user
|
50
|
-
self.user_requests = defaultdict(list)
|
51
|
-
|
52
|
-
async def dispatch(self, request: Request, call_next: Callable[[Request], Awaitable[Response]]) -> Response:
|
53
|
-
"""
|
54
|
-
Processes request and checks rate limit.
|
55
|
-
|
56
|
-
Args:
|
57
|
-
request: Request.
|
58
|
-
call_next: Next handler.
|
59
|
-
|
60
|
-
Returns:
|
61
|
-
Response.
|
62
|
-
"""
|
63
|
-
# Check if path is public
|
64
|
-
path = request.url.path
|
65
|
-
if self._is_public_path(path):
|
66
|
-
# If path is public, skip rate limiting
|
67
|
-
return await call_next(request)
|
68
|
-
|
69
|
-
# Current time
|
70
|
-
current_time = time.time()
|
71
|
-
|
72
|
-
# Get client IP address
|
73
|
-
client_ip = request.client.host if request.client else "unknown"
|
74
|
-
|
75
|
-
# Get user from request state (if any)
|
76
|
-
username = getattr(request.state, "username", None)
|
77
|
-
|
78
|
-
# Check limit by IP
|
79
|
-
if self.by_ip and client_ip != "unknown":
|
80
|
-
# Clean old requests
|
81
|
-
self._clean_old_requests(self.ip_requests[client_ip], current_time)
|
82
|
-
|
83
|
-
# Check number of requests
|
84
|
-
if len(self.ip_requests[client_ip]) >= self.rate_limit:
|
85
|
-
logger.warning(f"Rate limit exceeded for IP: {client_ip} | Path: {path}")
|
86
|
-
return self._create_error_response("Rate limit exceeded", 429)
|
87
|
-
|
88
|
-
# Add current request
|
89
|
-
self.ip_requests[client_ip].append(current_time)
|
90
|
-
|
91
|
-
# Check limit by user
|
92
|
-
if self.by_user and username:
|
93
|
-
# Clean old requests
|
94
|
-
self._clean_old_requests(self.user_requests[username], current_time)
|
95
|
-
|
96
|
-
# Check number of requests
|
97
|
-
if len(self.user_requests[username]) >= self.rate_limit:
|
98
|
-
logger.warning(f"Rate limit exceeded for user: {username} | Path: {path}")
|
99
|
-
return self._create_error_response("Rate limit exceeded", 429)
|
100
|
-
|
101
|
-
# Add current request
|
102
|
-
self.user_requests[username].append(current_time)
|
103
|
-
|
104
|
-
# Call the next middleware or main handler
|
105
|
-
return await call_next(request)
|
106
|
-
|
107
|
-
def _clean_old_requests(self, requests: List[float], current_time: float) -> None:
|
108
|
-
"""
|
109
|
-
Cleans old requests that are outside the time window.
|
110
|
-
|
111
|
-
Args:
|
112
|
-
requests: List of request timestamps.
|
113
|
-
current_time: Current time.
|
114
|
-
"""
|
115
|
-
min_time = current_time - self.time_window
|
116
|
-
while requests and requests[0] < min_time:
|
117
|
-
requests.pop(0)
|
118
|
-
|
119
|
-
def _is_public_path(self, path: str) -> bool:
|
120
|
-
"""
|
121
|
-
Checks if the path is public.
|
122
|
-
|
123
|
-
Args:
|
124
|
-
path: Path to check.
|
125
|
-
|
126
|
-
Returns:
|
127
|
-
True if path is public, False otherwise.
|
128
|
-
"""
|
129
|
-
return any(path.startswith(public_path) for public_path in self.public_paths)
|
130
|
-
|
131
|
-
def _create_error_response(self, message: str, status_code: int) -> Response:
|
132
|
-
"""
|
133
|
-
Creates error response in JSON-RPC format.
|
134
|
-
|
135
|
-
Args:
|
136
|
-
message: Error message.
|
137
|
-
status_code: HTTP status code.
|
138
|
-
|
139
|
-
Returns:
|
140
|
-
JSON response with error.
|
141
|
-
"""
|
142
|
-
return JSONResponse(
|
143
|
-
status_code=status_code,
|
144
|
-
content={
|
145
|
-
"jsonrpc": "2.0",
|
146
|
-
"error": {
|
147
|
-
"code": -32000,
|
148
|
-
"message": message
|
149
|
-
},
|
150
|
-
"id": None
|
151
|
-
}
|
152
|
-
)
|
@@ -1,125 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Reload Settings Command
|
3
|
-
|
4
|
-
This command allows reloading configuration settings from files and environment variables.
|
5
|
-
"""
|
6
|
-
|
7
|
-
from typing import Dict, Any
|
8
|
-
from mcp_proxy_adapter.commands.base import Command
|
9
|
-
from mcp_proxy_adapter.core.settings import reload_settings, get_custom_settings
|
10
|
-
from mcp_proxy_adapter.core.logging import get_logger
|
11
|
-
|
12
|
-
|
13
|
-
class ReloadSettingsResult:
|
14
|
-
"""
|
15
|
-
Result class for reload settings command.
|
16
|
-
"""
|
17
|
-
|
18
|
-
def __init__(
|
19
|
-
self,
|
20
|
-
success: bool,
|
21
|
-
message: str,
|
22
|
-
custom_settings: Dict[str, Any] = None,
|
23
|
-
error_message: str = None
|
24
|
-
):
|
25
|
-
self.success = success
|
26
|
-
self.message = message
|
27
|
-
self.custom_settings = custom_settings or {}
|
28
|
-
self.error_message = error_message
|
29
|
-
|
30
|
-
def to_dict(self) -> Dict[str, Any]:
|
31
|
-
"""Convert result to dictionary."""
|
32
|
-
result = {
|
33
|
-
"success": self.success,
|
34
|
-
"message": self.message,
|
35
|
-
"custom_settings": self.custom_settings
|
36
|
-
}
|
37
|
-
if self.error_message:
|
38
|
-
result["error_message"] = self.error_message
|
39
|
-
return result
|
40
|
-
|
41
|
-
def get_schema(self) -> Dict[str, Any]:
|
42
|
-
"""Get JSON schema for the result."""
|
43
|
-
return {
|
44
|
-
"type": "object",
|
45
|
-
"properties": {
|
46
|
-
"success": {
|
47
|
-
"type": "boolean",
|
48
|
-
"description": "Whether the operation was successful"
|
49
|
-
},
|
50
|
-
"message": {
|
51
|
-
"type": "string",
|
52
|
-
"description": "Operation result message"
|
53
|
-
},
|
54
|
-
"custom_settings": {
|
55
|
-
"type": "object",
|
56
|
-
"description": "Current custom settings after reload",
|
57
|
-
"additionalProperties": True
|
58
|
-
},
|
59
|
-
"error_message": {
|
60
|
-
"type": "string",
|
61
|
-
"description": "Error message if operation failed"
|
62
|
-
}
|
63
|
-
},
|
64
|
-
"required": ["success", "message", "custom_settings"]
|
65
|
-
}
|
66
|
-
|
67
|
-
|
68
|
-
class ReloadSettingsCommand(Command):
|
69
|
-
"""
|
70
|
-
Command to reload configuration settings.
|
71
|
-
"""
|
72
|
-
|
73
|
-
name = "reload_settings"
|
74
|
-
description = "Reload configuration settings from files and environment variables"
|
75
|
-
|
76
|
-
async def execute(self, **params) -> ReloadSettingsResult:
|
77
|
-
"""
|
78
|
-
Execute the reload settings command.
|
79
|
-
|
80
|
-
Args:
|
81
|
-
**params: Command parameters (not used)
|
82
|
-
|
83
|
-
Returns:
|
84
|
-
ReloadSettingsResult with operation status
|
85
|
-
"""
|
86
|
-
logger = get_logger("reload_settings_command")
|
87
|
-
|
88
|
-
try:
|
89
|
-
logger.info("🔄 Starting settings reload...")
|
90
|
-
|
91
|
-
# Reload configuration from files and environment variables
|
92
|
-
reload_settings()
|
93
|
-
|
94
|
-
# Get current custom settings
|
95
|
-
custom_settings = get_custom_settings()
|
96
|
-
|
97
|
-
logger.info("✅ Settings reloaded successfully")
|
98
|
-
logger.info(f"📋 Current custom settings: {custom_settings}")
|
99
|
-
|
100
|
-
return ReloadSettingsResult(
|
101
|
-
success=True,
|
102
|
-
message="Settings reloaded successfully from configuration files and environment variables",
|
103
|
-
custom_settings=custom_settings
|
104
|
-
)
|
105
|
-
|
106
|
-
except Exception as e:
|
107
|
-
error_msg = f"Failed to reload settings: {str(e)}"
|
108
|
-
logger.error(f"❌ {error_msg}")
|
109
|
-
|
110
|
-
return ReloadSettingsResult(
|
111
|
-
success=False,
|
112
|
-
message="Failed to reload settings",
|
113
|
-
custom_settings=get_custom_settings(),
|
114
|
-
error_message=error_msg
|
115
|
-
)
|
116
|
-
|
117
|
-
@classmethod
|
118
|
-
def get_schema(cls) -> Dict[str, Any]:
|
119
|
-
"""Get JSON schema for the command parameters."""
|
120
|
-
return {
|
121
|
-
"type": "object",
|
122
|
-
"description": "Reload configuration settings from files and environment variables",
|
123
|
-
"properties": {},
|
124
|
-
"additionalProperties": False
|
125
|
-
}
|