mcp-proxy-adapter 6.2.8__py3-none-any.whl → 6.2.11__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.
@@ -16,7 +16,7 @@ from mcp_proxy_adapter.api.app import create_app
16
16
 
17
17
  def main():
18
18
  """Main CLI entry point."""
19
- print("MCP Proxy Adapter v6.2.8")
19
+ print("MCP Proxy Adapter v6.2.9")
20
20
  print("========================")
21
21
  print()
22
22
  print("Usage:")
@@ -7,6 +7,7 @@ import ssl
7
7
  from pathlib import Path
8
8
  from typing import Any, Dict, List, Optional, Union
9
9
  from contextlib import asynccontextmanager
10
+ import asyncio
10
11
 
11
12
  from fastapi import FastAPI, Body, Depends, HTTPException, Request
12
13
  from fastapi.responses import JSONResponse, Response
@@ -41,8 +42,19 @@ def create_lifespan(config_path: Optional[str] = None):
41
42
  """
42
43
  # Startup events
43
44
  from mcp_proxy_adapter.commands.command_registry import registry
44
- from mcp_proxy_adapter.core.proxy_registration import register_with_proxy, unregister_from_proxy
45
+ from mcp_proxy_adapter.core.proxy_registration import (
46
+ register_with_proxy,
47
+ unregister_from_proxy,
48
+ initialize_proxy_registration,
49
+ )
45
50
 
51
+ # Initialize proxy registration manager WITH CURRENT CONFIG before reload_system
52
+ # so that registration inside reload_system can work
53
+ try:
54
+ initialize_proxy_registration(config.get_all())
55
+ except Exception as e:
56
+ logger.error(f"Failed to initialize proxy registration: {e}")
57
+
46
58
  # Initialize system using unified logic
47
59
  # This will load config, register custom commands, and discover auto-commands
48
60
  # Only reload config if not already loaded from the same path
@@ -54,7 +66,13 @@ def create_lifespan(config_path: Optional[str] = None):
54
66
  logger.info(f"Application started with {init_result['total_commands']} commands registered")
55
67
  logger.info(f"System initialization result: {init_result}")
56
68
 
57
- # Register with proxy if enabled
69
+ # Initialize proxy registration manager with current config
70
+ try:
71
+ initialize_proxy_registration(config.get_all())
72
+ except Exception as e:
73
+ logger.error(f"Failed to initialize proxy registration: {e}")
74
+
75
+ # Register with proxy if enabled (run slightly delayed to ensure server is accepting connections)
58
76
  server_config = config.get("server", {})
59
77
  server_host = server_config.get("host", "0.0.0.0")
60
78
  server_port = server_config.get("port", 8000)
@@ -79,12 +97,19 @@ def create_lifespan(config_path: Optional[str] = None):
79
97
 
80
98
  server_url = f"{protocol}://{server_host}:{server_port}"
81
99
 
82
- # Attempt proxy registration
83
- registration_success = await register_with_proxy(server_url)
84
- if registration_success:
85
- logger.info("✅ Proxy registration completed successfully")
86
- else:
87
- logger.info("ℹ️ Proxy registration is disabled or failed")
100
+ # Attempt proxy registration in background with small delay
101
+ async def _delayed_register():
102
+ try:
103
+ await asyncio.sleep(0.5)
104
+ success = await register_with_proxy(server_url)
105
+ if success:
106
+ logger.info("✅ Proxy registration completed successfully")
107
+ else:
108
+ logger.info("ℹ️ Proxy registration is disabled or failed")
109
+ except Exception as e:
110
+ logger.error(f"Proxy registration failed: {e}")
111
+
112
+ asyncio.create_task(_delayed_register())
88
113
 
89
114
  yield # Application is running
90
115
 
@@ -13,4 +13,4 @@ Examples include:
13
13
  For detailed documentation, see the main README.md file.
14
14
  """
15
15
 
16
- __version__ = "6.2.8"
16
+ __version__ = "6.2.9"
@@ -15,6 +15,18 @@ def generate_http_simple_config(port: int = 8000) -> Dict[str, Any]:
15
15
  "server": {"host": "127.0.0.1", "port": port},
16
16
  "ssl": {"enabled": False},
17
17
  "security": {"enabled": False},
18
+ "registration": {
19
+ "enabled": True,
20
+ "auth_method": "token",
21
+ "server_url": "http://127.0.0.1:3004/proxy",
22
+ "token": {"enabled": True, "token": "proxy_registration_token_123"},
23
+ "proxy_info": {
24
+ "name": "mcp_example_server",
25
+ "capabilities": ["jsonrpc", "rest", "proxy_registration"],
26
+ "endpoints": {"jsonrpc": "/api/jsonrpc", "rest": "/cmd", "health": "/health"}
27
+ },
28
+ "heartbeat": {"enabled": True, "interval": 30}
29
+ },
18
30
  "protocols": {"enabled": True, "allowed_protocols": ["http"]}
19
31
  }
20
32
  def generate_http_token_config(port: int = 8001) -> Dict[str, Any]:
@@ -86,6 +98,18 @@ def generate_mtls_with_roles_config(port: int = 8005) -> Dict[str, Any]:
86
98
  "ca_cert": "./certs/ca_cert.pem",
87
99
  "verify_client": True
88
100
  },
101
+ "registration": {
102
+ "enabled": True,
103
+ "auth_method": "token",
104
+ "server_url": "http://127.0.0.1:3004/proxy",
105
+ "token": {"enabled": True, "token": "proxy_registration_token_123"},
106
+ "proxy_info": {
107
+ "name": "mcp_example_server",
108
+ "capabilities": ["jsonrpc", "rest", "security", "proxy_registration"],
109
+ "endpoints": {"jsonrpc": "/api/jsonrpc", "rest": "/cmd", "health": "/health"}
110
+ },
111
+ "heartbeat": {"enabled": True, "interval": 30}
112
+ },
89
113
  "security": {
90
114
  "enabled": True,
91
115
  "auth": {"enabled": True, "methods": ["certificate"]},
@@ -0,0 +1,144 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Author: Vasiliy Zdanovskiy
4
+ email: vasilyvz@gmail.com
5
+
6
+ Lightweight local proxy server for MCP Proxy Adapter examples.
7
+
8
+ This server provides proxy registration endpoints at /proxy for adapter instances
9
+ to register/unregister/heartbeat and for simple discovery.
10
+ """
11
+
12
+ import argparse
13
+ import asyncio
14
+ import signal
15
+ import sys
16
+ from typing import Dict, List, Optional
17
+ import json
18
+ from datetime import datetime, timedelta
19
+
20
+ from fastapi import FastAPI, HTTPException
21
+ from pydantic import BaseModel
22
+ import uvicorn
23
+
24
+
25
+ # Simple in-memory storage for registered adapters
26
+ registered_adapters: Dict[str, Dict] = {}
27
+
28
+
29
+ class AdapterRegistration(BaseModel):
30
+ name: str
31
+ url: str
32
+ capabilities: List[str]
33
+ metadata: Optional[Dict] = {}
34
+
35
+
36
+ class ProxyRouter:
37
+ """Simple proxy router for MCP examples."""
38
+
39
+ def __init__(self):
40
+ self.app = FastAPI(title="MCP Local Proxy", version="1.0.0")
41
+ self._setup_routes()
42
+
43
+ def _setup_routes(self):
44
+ @self.app.post("/proxy/register")
45
+ async def register_adapter(registration: AdapterRegistration):
46
+ """Register an adapter with the proxy."""
47
+ adapter_id = registration.name
48
+ registered_adapters[adapter_id] = {
49
+ "name": registration.name,
50
+ "url": registration.url,
51
+ "capabilities": registration.capabilities,
52
+ "metadata": registration.metadata,
53
+ "registered_at": datetime.now().isoformat(),
54
+ "last_heartbeat": datetime.now().isoformat(),
55
+ "status": "active"
56
+ }
57
+ print(f"✅ Registered adapter: {adapter_id} at {registration.url}")
58
+ return {"status": "registered", "adapter_id": adapter_id}
59
+
60
+ @self.app.post("/proxy/unregister")
61
+ async def unregister_adapter(adapter_id: str):
62
+ """Unregister an adapter from the proxy."""
63
+ if adapter_id in registered_adapters:
64
+ del registered_adapters[adapter_id]
65
+ print(f"✅ Unregistered adapter: {adapter_id}")
66
+ return {"status": "unregistered", "adapter_id": adapter_id}
67
+ else:
68
+ raise HTTPException(status_code=404, detail="Adapter not found")
69
+
70
+ @self.app.get("/proxy/list")
71
+ async def list_adapters():
72
+ """List all registered adapters."""
73
+ return {
74
+ "adapters": list(registered_adapters.values()),
75
+ "count": len(registered_adapters)
76
+ }
77
+
78
+ @self.app.get("/proxy/health")
79
+ async def health_check():
80
+ """Health check endpoint."""
81
+ return {
82
+ "status": "healthy",
83
+ "timestamp": datetime.now().isoformat(),
84
+ "adapters_count": len(registered_adapters)
85
+ }
86
+
87
+ @self.app.post("/proxy/heartbeat")
88
+ async def heartbeat(adapter_id: str):
89
+ """Receive heartbeat from adapter."""
90
+ if adapter_id in registered_adapters:
91
+ registered_adapters[adapter_id]["last_heartbeat"] = datetime.now().isoformat()
92
+ return {"status": "ok", "adapter_id": adapter_id}
93
+ else:
94
+ raise HTTPException(status_code=404, detail="Adapter not found")
95
+
96
+
97
+ def create_proxy_app() -> FastAPI:
98
+ """Create FastAPI app with proxy endpoints."""
99
+ router = ProxyRouter()
100
+ return router.app
101
+
102
+
103
+ def main() -> None:
104
+ parser = argparse.ArgumentParser(description="Run local proxy server for MCP examples")
105
+ parser.add_argument("--host", default="127.0.0.1", help="Host to bind to (default: 127.0.0.1)")
106
+ parser.add_argument("--port", type=int, default=3004, help="Port to bind to (default: 3004)")
107
+ parser.add_argument("--log-level", default="info", choices=["debug", "info", "warning", "error"], help="Log level")
108
+
109
+ args = parser.parse_args()
110
+
111
+ # Create FastAPI app
112
+ app = create_proxy_app()
113
+
114
+ # Setup graceful shutdown
115
+ def signal_handler(signum, frame):
116
+ print("\n🛑 Shutting down proxy server...")
117
+ sys.exit(0)
118
+
119
+ signal.signal(signal.SIGINT, signal_handler)
120
+ signal.signal(signal.SIGTERM, signal_handler)
121
+
122
+ print("🚀 Starting MCP Local Proxy Server...")
123
+ print(f"📡 Server URL: http://{args.host}:{args.port}")
124
+ print(f"🔗 Proxy endpoints available at: http://{args.host}:{args.port}/proxy")
125
+ print("📋 Supported endpoints:")
126
+ print(" POST /proxy/register - Register adapter")
127
+ print(" POST /proxy/unregister - Unregister adapter")
128
+ print(" GET /proxy/list - List registered adapters")
129
+ print(" GET /proxy/health - Health check")
130
+ print(" POST /proxy/heartbeat - Heartbeat from adapter")
131
+ print("⚡ Press Ctrl+C to stop\n")
132
+
133
+ # Run server
134
+ uvicorn.run(
135
+ app,
136
+ host=args.host,
137
+ port=args.port,
138
+ log_level=args.log_level,
139
+ access_log=True
140
+ )
141
+
142
+
143
+ if __name__ == "__main__":
144
+ main()
@@ -274,9 +274,26 @@ def main():
274
274
  parser.add_argument("--no-cleanup", action="store_true", help="Don't cleanup servers after tests")
275
275
  parser.add_argument("--verbose", "-v", action="store_true", help="Verbose output")
276
276
  args = parser.parse_args()
277
- # Change to examples directory
278
- examples_dir = Path(__file__).parent
279
- os.chdir(examples_dir)
277
+
278
+ # Determine the correct configs directory
279
+ current_dir = Path.cwd()
280
+ if (current_dir / "configs").exists():
281
+ # We're in the test environment root directory
282
+ configs_dir = current_dir / "configs"
283
+ os.chdir(current_dir) # Stay in current directory
284
+ elif (Path(__file__).parent.parent / "configs").exists():
285
+ # We're running from package installation, configs is relative to examples
286
+ configs_dir = Path(__file__).parent.parent / "configs"
287
+ os.chdir(Path(__file__).parent.parent) # Change to parent of examples
288
+ else:
289
+ # Try to find configs relative to examples directory
290
+ examples_dir = Path(__file__).parent
291
+ configs_dir = examples_dir / "configs"
292
+ os.chdir(examples_dir)
293
+
294
+ print(f"🔍 Using configs directory: {configs_dir}")
295
+ print(f"🔍 Working directory: {Path.cwd()}")
296
+
280
297
  # Create and run test runner
281
298
  runner = SecurityTestRunner()
282
299
  try:
@@ -2,5 +2,5 @@
2
2
  Version information for MCP Proxy Adapter.
3
3
  """
4
4
 
5
- __version__ = "6.2.8"
5
+ __version__ = "6.2.9"
6
6
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mcp-proxy-adapter
3
- Version: 6.2.8
3
+ Version: 6.2.11
4
4
  Summary: Powerful JSON-RPC microservices framework with built-in security, authentication, and proxy registration
5
5
  Home-page: https://github.com/maverikod/mcp-proxy-adapter
6
6
  Author: Vasiliy Zdanovskiy
@@ -650,7 +650,7 @@ MIT License - see [LICENSE](https://github.com/maverikod/mcp-proxy-adapter/blob/
650
650
 
651
651
  ## 📊 Version
652
652
 
653
- **6.2.8** - Production-ready release with comprehensive security, proxy registration, and PyPI optimization.
653
+ **6.2.9** - Production-ready release with comprehensive security, proxy registration, and PyPI optimization.
654
654
 
655
655
  ---
656
656
 
@@ -1,12 +1,12 @@
1
1
  mcp_proxy_adapter/__init__.py,sha256=B7m1YWyv_Wb87-Q-JqVpHQgwajnfIgDyZ_iIxzdTbBY,1021
2
- mcp_proxy_adapter/__main__.py,sha256=Bt1ONguFhFkHo2lrbfpBqLt_2896rkw165HQtDDT7Ys,768
2
+ mcp_proxy_adapter/__main__.py,sha256=yGVhvEcu-PyoTSWhYbRYMMJ3qfp2mlT59s8LWNuu5Vk,768
3
3
  mcp_proxy_adapter/config.py,sha256=z4rUbJdxYj6vYw05OM_kMXs1Qn2HRQXGHI9PB4hgPd4,12867
4
4
  mcp_proxy_adapter/custom_openapi.py,sha256=jYUrCy8C1mShh3sjKj-JkzSMLAvxDLTvtzSJFj5HUNg,15023
5
5
  mcp_proxy_adapter/main.py,sha256=_DJwMZdN0393UR-U7xfQh59EpbDDgv1oWPFf-v2MoII,2147
6
6
  mcp_proxy_adapter/openapi.py,sha256=36vOEbJjGnVZR6hUhl6mHCD29HYOEFKo2bL0JdGSm-4,13952
7
- mcp_proxy_adapter/version.py,sha256=wehJCAiczZs9JWXECcyMYJw_dsc9e9JXRgLJ4u7wfYo,75
7
+ mcp_proxy_adapter/version.py,sha256=DBoduPI-4-pzZQM7yaYwnDNFnd9nsp28dIO7Sk1N9CI,75
8
8
  mcp_proxy_adapter/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
- mcp_proxy_adapter/api/app.py,sha256=pYrsDWhZAYoYbxujD0MGeOWdTnBUGueIGmZqeAbaB9A,27884
9
+ mcp_proxy_adapter/api/app.py,sha256=khl4kaI4mJ6dNbfAK7hR97Ek-eWC9NBeuXHr6GVbLoU,28911
10
10
  mcp_proxy_adapter/api/handlers.py,sha256=DcZT7MVBV33q-0EJ0iFqxE0VgBkFt6d_SqoRkntwyvc,8477
11
11
  mcp_proxy_adapter/api/schemas.py,sha256=xOmiSwHaapY6myEFnLu7o-LWVPM7vwmLYZXFo2c6NfE,12381
12
12
  mcp_proxy_adapter/api/tool_integration.py,sha256=MrtX7vUXCGBBuZuOs3C6EF67R_U_0xMfOmlmsAz-wuE,10245
@@ -80,7 +80,7 @@ mcp_proxy_adapter/core/ssl_utils.py,sha256=_2mhpuoiRpSbUBifnQvtuziQfBRrXQUKtB58A
80
80
  mcp_proxy_adapter/core/transport_manager.py,sha256=ppcgjO-7Ulrk1ovlzlXVM89Iw4VOGA3awKgLf7FFAJ0,9518
81
81
  mcp_proxy_adapter/core/unified_config_adapter.py,sha256=cpN_VrliIFGDH3JsfRkTlFdQvLcmuMYYedq0QEzlb0Y,22857
82
82
  mcp_proxy_adapter/core/utils.py,sha256=ly8Ttg2v1OBukThJLxudRvmttU1hxJFLJUfat4b2dOI,3268
83
- mcp_proxy_adapter/examples/__init__.py,sha256=XW59G9uq5eddAfxSzXOnusji40gfaZ9EYIPCVd2lCDc,449
83
+ mcp_proxy_adapter/examples/__init__.py,sha256=o2eYCxm2VUaZWsm-XSUAT7x2SyJKF27jofJwWOIZVXo,449
84
84
  mcp_proxy_adapter/examples/create_certificates_simple.py,sha256=2KS-s3amvAqasvdh-cxY7ARuFAHVjtbtr_EJF2SKVQ0,23221
85
85
  mcp_proxy_adapter/examples/debug_request_state.py,sha256=x_H3NIlkmIS6lZimvEM6kCXxGdpgFw99Sdui8qa_qeU,4347
86
86
  mcp_proxy_adapter/examples/debug_role_chain.py,sha256=33l2Tk5mrcnwPFwqm2NTHcrWaJrXUU2wxW2I6Y4uIg4,8344
@@ -88,10 +88,11 @@ mcp_proxy_adapter/examples/demo_client.py,sha256=inic-FP5qG8oQXUaCrtEhmhac_PDZ1p
88
88
  mcp_proxy_adapter/examples/generate_all_certificates.py,sha256=rgcwqIkQ1eDfEIRFRXGIOz-jOSS1w0GPBRhYvMl6Vjc,16948
89
89
  mcp_proxy_adapter/examples/generate_certificates.py,sha256=A34OHUEiFvINOHrm3_JiDSbp-WG-eQXIvKCsE8JAeXQ,6616
90
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=AJqsB7sP-tYuOD49MiWBo-CkpdRd92XYQ8m31rPFiFg,8495
91
+ mcp_proxy_adapter/examples/generate_test_configs.py,sha256=a622rSfcEkpx63wfoalGHs2IWU5B-dtzU7_ZYIvEhCM,9621
92
92
  mcp_proxy_adapter/examples/proxy_registration_example.py,sha256=g59_QG2D1CCqhIXEvgy2XmgXI3toLmLyH7hL3uHZwC8,12647
93
93
  mcp_proxy_adapter/examples/run_example.py,sha256=o8rcy9Xo0UuZG4MpKdex3pFWYdtAi6uW8dEBQE6Yzbw,2539
94
- mcp_proxy_adapter/examples/run_security_tests.py,sha256=s8hOcq-dqhzVU3ikuefLEK2IkmE7WNlKGSjj0lEVHHk,12287
94
+ mcp_proxy_adapter/examples/run_proxy_server.py,sha256=MF5lWqARgeaQN0Eb27rdFquBdbTeSXJDz0kaJTQm62w,4959
95
+ mcp_proxy_adapter/examples/run_security_tests.py,sha256=V1DZ3GWx-5FmEPRuGWIJ6cgsog6bBNgdX3HT0xq6j-U,13055
95
96
  mcp_proxy_adapter/examples/run_security_tests_fixed.py,sha256=fNQsbALf9548xJ0OGPKYx5Crzg1GbcL8CSh1x_oKu_A,10540
96
97
  mcp_proxy_adapter/examples/security_test_client.py,sha256=eBy6pZ5Dhdo-qi_7Fk-IWGHq7zAJA-om8RBuOep4XSs,28022
97
98
  mcp_proxy_adapter/examples/setup_test_environment.py,sha256=Y6oNaR95Rmn2csupYoGV-_mMF6AtqJ31vwLhY0TQtMk,11319
@@ -113,8 +114,8 @@ mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.
113
114
  mcp_proxy_adapter/examples/full_application/hooks/__init__.py,sha256=ORG4cL8cSXEMmZ0CEPz75OVuwg54pdDm2GIBpP4dtcs,200
114
115
  mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py,sha256=TYXuHI-KW_mH5r8mSKgNMJCr3moeEKrqC4Eex0U298k,3457
115
116
  mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py,sha256=IaskSrckZS6bE3aGxSBL8aTj-iJTSI2ysfsFjhjncyM,2975
116
- mcp_proxy_adapter-6.2.8.dist-info/licenses/LICENSE,sha256=6KdtUcTwmTRbJrAmYjVn7e6S-V42ubeDJ-AiVEzZ510,1075
117
- mcp_proxy_adapter-6.2.8.dist-info/METADATA,sha256=lsVvTJKSGfA8Ncg7FUK9rVpeUKIdUvkJMxzHZt0DGEI,22198
118
- mcp_proxy_adapter-6.2.8.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
119
- mcp_proxy_adapter-6.2.8.dist-info/top_level.txt,sha256=JZT7vPLBYrtroX-ij68JBhJYbjDdghcV-DFySRy-Nnw,18
120
- mcp_proxy_adapter-6.2.8.dist-info/RECORD,,
117
+ mcp_proxy_adapter-6.2.11.dist-info/licenses/LICENSE,sha256=6KdtUcTwmTRbJrAmYjVn7e6S-V42ubeDJ-AiVEzZ510,1075
118
+ mcp_proxy_adapter-6.2.11.dist-info/METADATA,sha256=7nVr-b4gD97xuuGvOKbi1jS29GxZB0bQFrmb2QA5Cbs,22199
119
+ mcp_proxy_adapter-6.2.11.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
120
+ mcp_proxy_adapter-6.2.11.dist-info/top_level.txt,sha256=JZT7vPLBYrtroX-ij68JBhJYbjDdghcV-DFySRy-Nnw,18
121
+ mcp_proxy_adapter-6.2.11.dist-info/RECORD,,