diff --git a/mcp/server.py b/mcp/server.py index 4ebe85f..2c35442 100644 --- a/mcp/server.py +++ b/mcp/server.py @@ -601,8 +601,15 @@ def restore_servers_from_config() -> int: def haproxy_list_domains() -> str: """List all configured domains with their backend servers. + Shows all domains mapped in HAProxy with their pool backend and configured servers. + Returns: - List of domains with their associated backend servers + List of domains in format: domain -> pool_N (pool): server=ip:port + + Example: + # Output: + # • api.example.com -> pool_1 (pool): pool_1_1=10.0.0.1:8080, pool_1_2=10.0.0.2:8080 + # • web.example.com -> pool_2 (pool): pool_2_1=10.0.0.3:80 """ try: domains = [] @@ -641,6 +648,9 @@ def haproxy_list_domains() -> str: def haproxy_add_domain(domain: str, ip: str = "", http_port: int = 80) -> str: """Add a new domain to HAProxy using map-based routing (no reload required). + Creates a domain mapping to a pool backend. Each domain can have up to 10 + backend servers for load balancing. Use haproxy_add_server to add more servers. + Args: domain: The domain name to add (e.g., api.example.com) ip: Optional IP address for initial server; if provided, adds to slot 1 @@ -648,6 +658,13 @@ def haproxy_add_domain(domain: str, ip: str = "", http_port: int = 80) -> str: Returns: Success message or error description + + Example: + # Add domain without server (add servers later) + haproxy_add_domain("api.example.com") + + # Add domain with initial server + haproxy_add_domain("api.example.com", ip="10.0.0.1", http_port=8080) """ # Validate inputs if not validate_domain(domain): @@ -754,11 +771,19 @@ def haproxy_remove_domain(domain: str) -> str: def haproxy_list_servers(domain: str) -> str: """List all servers for a specific domain. + Shows all configured servers with their slot numbers, addresses, and status. + Use this to see which slots are in use before adding or removing servers. + Args: domain: The domain name to list servers for Returns: - List of servers with their addresses and status + List of servers with slot number, address (ip:port), and status (UP/DOWN/MAINT) + + Example: + haproxy_list_servers("api.example.com") + # Output: pool_1_1: 10.0.0.1:8080 (UP) + # pool_1_2: 10.0.0.2:8080 (UP) """ if not validate_domain(domain): return "Error: Invalid domain format" @@ -789,14 +814,26 @@ def haproxy_list_servers(domain: str) -> str: def haproxy_add_server(domain: str, slot: int, ip: str, http_port: int = 80) -> str: """Add a server to a domain's backend at specified slot. + Each domain can have up to 10 servers (slots 1-10) for load balancing. + To add multiple servers, call this with different slot numbers. + HAProxy distributes traffic across all configured servers using round-robin. + Args: domain: The domain name to add the server to - slot: Server slot number (1 to MAX_SLOTS) + slot: Server slot number (1-10). Use different slots for multiple servers ip: IP address of the server (required) http_port: HTTP port (default: 80) Returns: Success message or error description + + Example: + # Add two servers for load balancing + haproxy_add_server("api.example.com", slot=1, ip="10.0.0.1", http_port=8080) + haproxy_add_server("api.example.com", slot=2, ip="10.0.0.2", http_port=8080) + + # Add a third server + haproxy_add_server("api.example.com", slot=3, ip="10.0.0.3", http_port=8080) """ if not validate_domain(domain): return "Error: Invalid domain format" @@ -831,12 +868,19 @@ def haproxy_add_server(domain: str, slot: int, ip: str, http_port: int = 80) -> def haproxy_remove_server(domain: str, slot: int) -> str: """Remove a server from a domain's backend at specified slot. + Removes the server from load balancing rotation. Use haproxy_list_servers + to see which slots are in use before removing. + Args: domain: The domain name to remove the server from - slot: Server slot number (1 to MAX_SLOTS) to remove + slot: Server slot number (1-10) to remove Returns: Success message or error description + + Example: + # Remove server at slot 2 + haproxy_remove_server("api.example.com", slot=2) """ if not validate_domain(domain): return "Error: Invalid domain format" @@ -887,10 +931,19 @@ def haproxy_stats() -> str: @mcp.tool() def haproxy_health() -> str: - """Check health of MCP server and HAProxy connectivity. + """Check overall system health (MCP server, HAProxy, config files). + + Use this for monitoring integration. Returns "healthy" if all components are OK. Returns: - JSON with health status of MCP server, HAProxy, and configuration files + JSON with: + - status: "healthy" or "unhealthy" + - components.mcp: MCP server status + - components.haproxy: HAProxy connectivity, version, uptime + - components.config_files: map_file and servers_file accessibility + + Example: + # Returns: {"status": "healthy", "components": {"mcp": {"status": "ok"}, ...}} """ result: Dict[str, Any] = { "status": "healthy", @@ -938,11 +991,20 @@ def haproxy_health() -> str: def haproxy_domain_health(domain: str) -> str: """Check health status of backend servers for a specific domain. + Returns detailed health information for all servers in the domain's backend. + Args: domain: The domain name to check health for Returns: - JSON with domain health status including each server's state + JSON with: + - status: "healthy" (all UP), "degraded" (partial UP), "down" (all DOWN), "no_servers" + - servers: list with name, addr, status (UP/DOWN), check_status (L4OK/L4TOUT/L4CON) + - healthy_count/total_count: server counts + + Example: + haproxy_domain_health("api.example.com") + # Returns: {"status": "healthy", "servers": [...], "healthy_count": 2, "total_count": 2} """ if not validate_domain(domain): return json.dumps({"error": "Invalid domain format"}) @@ -1061,15 +1123,27 @@ def haproxy_list_frontends() -> str: @mcp.tool() def haproxy_set_server_state(backend: str, server: str, state: str) -> str: - """Set server state. States: ready (enable), drain (graceful shutdown), maint (maintenance/disable) + """Set server state for maintenance or traffic control. + + Use haproxy_list_servers to get the backend and server names. Args: - backend: Backend name (alphanumeric, underscore, hyphen only) - server: Server name within the backend - state: Target state - ready, drain, or maint + backend: Backend name (e.g., "pool_1" from haproxy_list_servers) + server: Server name (e.g., "pool_1_1" from haproxy_list_servers) + state: Target state: + - ready: Enable server for traffic + - drain: Stop new connections, finish existing (graceful shutdown) + - maint: Disable completely (maintenance mode) Returns: Success message or error description + + Example: + # Put server in maintenance + haproxy_set_server_state("pool_1", "pool_1_2", "maint") + + # Re-enable server + haproxy_set_server_state("pool_1", "pool_1_2", "ready") """ if not validate_backend_name(backend): return "Error: Invalid backend name (use alphanumeric, underscore, hyphen only)" @@ -1086,13 +1160,19 @@ def haproxy_set_server_state(backend: str, server: str, state: str) -> str: @mcp.tool() def haproxy_get_server_health(backend: str = "") -> str: - """Get health status of all servers or servers in a specific backend. + """Get health status of all servers (low-level view across all backends). + + For domain-specific health, use haproxy_domain_health instead. Args: - backend: Optional backend name to filter results + backend: Optional backend name to filter (e.g., "pool_1"). If empty, shows all. Returns: - Server health status or error description + List of servers with status: UP (healthy), DOWN (failed), MAINT (maintenance) + + Example: + haproxy_get_server_health() # All servers + haproxy_get_server_health("pool_1") # Only pool_1 backend """ if backend and not validate_backend_name(backend): return "Error: Invalid backend name (use alphanumeric, underscore, hyphen only)" @@ -1114,15 +1194,25 @@ def haproxy_get_server_health(backend: str = "") -> str: @mcp.tool() def haproxy_set_server_weight(backend: str, server: str, weight: int) -> str: - """Set server weight (0-256). Weight 0 disables the server for new connections. + """Set server weight for load balancing ratio control. + + Higher weight = more traffic. Default is 1. Use 0 to disable without maintenance mode. Args: - backend: Backend name (alphanumeric, underscore, hyphen only) - server: Server name within the backend - weight: Server weight from 0 to 256 + backend: Backend name (e.g., "pool_1") + server: Server name (e.g., "pool_1_1") + weight: Weight 0-256 (0 disables, higher = more traffic) Returns: Success message or error description + + Example: + # Send 2x traffic to server 1 vs server 2 + haproxy_set_server_weight("pool_1", "pool_1_1", 2) + haproxy_set_server_weight("pool_1", "pool_1_2", 1) + + # Temporarily disable server (soft disable, not maintenance) + haproxy_set_server_weight("pool_1", "pool_1_3", 0) """ if not validate_backend_name(backend): return "Error: Invalid backend name (use alphanumeric, underscore, hyphen only)" @@ -1139,13 +1229,20 @@ def haproxy_set_server_weight(backend: str, server: str, weight: int) -> str: @mcp.tool() def haproxy_get_connections(backend: str = "") -> str: - """Get active connections per server. + """Get active connection counts per server. + + Useful for monitoring traffic distribution and identifying hot spots. Args: - backend: Optional backend name to filter results + backend: Optional backend name to filter (e.g., "pool_1"). If empty, shows all. Returns: - Connection statistics or error description + List of servers with current active connections + + Example: + haproxy_get_connections() # All backends + haproxy_get_connections("pool_1") # Only pool_1 + # Output: pool_1/pool_1_1: 5 active connections """ if backend and not validate_backend_name(backend): return "Error: Invalid backend name (use alphanumeric, underscore, hyphen only)"