mcp-proxy-adapter 6.2.9__py3-none-any.whl → 6.2.12__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.
@@ -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
 
@@ -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]:
@@ -71,7 +83,7 @@ def generate_mtls_no_roles_config(port: int = 8004) -> Dict[str, Any]:
71
83
  "security": {
72
84
  "enabled": True,
73
85
  "auth": {"enabled": True, "methods": ["certificate"]},
74
- "permissions": {"enabled": False}
86
+ "permissions": {"enabled": False, "roles_file": "./roles.json"}
75
87
  },
76
88
  "protocols": {"enabled": True, "allowed_protocols": ["https", "mtls"]}
77
89
  }
@@ -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()
@@ -42,20 +42,20 @@ class SecurityTestRunner:
42
42
  },
43
43
  "https": {
44
44
  "config": "configs/https_simple.json",
45
- "port": 8443,
46
- "url": "https://localhost:8443",
45
+ "port": 8002,
46
+ "url": "https://localhost:8002",
47
47
  "auth": "none"
48
48
  },
49
49
  "https_token": {
50
50
  "config": "configs/https_token.json",
51
- "port": 8444,
52
- "url": "https://localhost:8444",
51
+ "port": 8003,
52
+ "url": "https://localhost:8003",
53
53
  "auth": "api_key"
54
54
  },
55
55
  "mtls": {
56
- "config": "configs/mtls_with_roles.json",
57
- "port": 8445,
58
- "url": "https://localhost:8445",
56
+ "config": "configs/mtls_no_roles.json",
57
+ "port": 8004,
58
+ "url": "https://localhost:8004",
59
59
  "auth": "certificate"
60
60
  }
61
61
  }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mcp-proxy-adapter
3
- Version: 6.2.9
3
+ Version: 6.2.12
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
@@ -6,7 +6,7 @@ mcp_proxy_adapter/main.py,sha256=_DJwMZdN0393UR-U7xfQh59EpbDDgv1oWPFf-v2MoII,214
6
6
  mcp_proxy_adapter/openapi.py,sha256=36vOEbJjGnVZR6hUhl6mHCD29HYOEFKo2bL0JdGSm-4,13952
7
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
@@ -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=JFPays1tluGFpvo8FLjpo5FQ1HK8v1aGbb1knBokp9Q,9651
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=V1DZ3GWx-5FmEPRuGWIJ6cgsog6bBNgdX3HT0xq6j-U,13055
94
+ mcp_proxy_adapter/examples/run_proxy_server.py,sha256=MF5lWqARgeaQN0Eb27rdFquBdbTeSXJDz0kaJTQm62w,4959
95
+ mcp_proxy_adapter/examples/run_security_tests.py,sha256=YX_l69DmNIA36TTaLB_xAA1XraJJjg0Hev-xbICMQxA,13053
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.9.dist-info/licenses/LICENSE,sha256=6KdtUcTwmTRbJrAmYjVn7e6S-V42ubeDJ-AiVEzZ510,1075
117
- mcp_proxy_adapter-6.2.9.dist-info/METADATA,sha256=OdRrUBeEOGwjimLhp6GTFH8MnekCJ2DG-9iwf3oc-uk,22198
118
- mcp_proxy_adapter-6.2.9.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
119
- mcp_proxy_adapter-6.2.9.dist-info/top_level.txt,sha256=JZT7vPLBYrtroX-ij68JBhJYbjDdghcV-DFySRy-Nnw,18
120
- mcp_proxy_adapter-6.2.9.dist-info/RECORD,,
117
+ mcp_proxy_adapter-6.2.12.dist-info/licenses/LICENSE,sha256=6KdtUcTwmTRbJrAmYjVn7e6S-V42ubeDJ-AiVEzZ510,1075
118
+ mcp_proxy_adapter-6.2.12.dist-info/METADATA,sha256=Mvd9YJsmXK-oaTx6VuK5Yi7Dr1yLAfRThSxwF7itzZg,22199
119
+ mcp_proxy_adapter-6.2.12.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
120
+ mcp_proxy_adapter-6.2.12.dist-info/top_level.txt,sha256=JZT7vPLBYrtroX-ij68JBhJYbjDdghcV-DFySRy-Nnw,18
121
+ mcp_proxy_adapter-6.2.12.dist-info/RECORD,,