diff --git a/app/mcp_server.py b/app/mcp_server.py index ef91359..58ef030 100644 --- a/app/mcp_server.py +++ b/app/mcp_server.py @@ -267,6 +267,18 @@ async def handle_list_tools() -> list[Tool]: "active_only": {"type": "boolean", "description": "Hanya tampilkan gateway yang aktif (default: true)."}, }, }, + ), + Tool( + name="get_interface_traffic", + description="Mendapatkan traffic rate (tx/rx) interface dalam format Mbps yang mudah dibaca.", + inputSchema={ + "type": "object", + "properties": { + "router_name": {"type": "string", "description": "Nama router."}, + "interface_name": {"type": "string", "description": "Nama interface spesifik (opsional, jika kosong tampilkan semua yang running)."}, + "running_only": {"type": "boolean", "description": "Hanya tampilkan interface yang aktif (default: true)."}, + }, + }, ) ] @@ -658,6 +670,82 @@ async def handle_call_tool(name: str, arguments: dict | None) -> list[TextConten return [TextContent(type="text", text=json.dumps(result, indent=2))] + elif name == "get_interface_traffic": + interfaces = fetch_data("interface", auth, base_url) + + # Filter by running only (default true) + running_only = arguments.get("running_only", True) if arguments else True + if running_only: + interfaces = [i for i in interfaces if i.get("running") == "true" or i.get("running") is True] + + # Filter by specific interface name if provided + interface_name = arguments.get("interface_name") if arguments else None + if interface_name: + interfaces = [i for i in interfaces if i.get("name", "").lower() == interface_name.lower()] + + def bytes_to_mbps(bytes_val): + """Convert bytes to Mbps (bits per second / 1,000,000)""" + try: + return round(float(bytes_val) * 8 / 1_000_000, 2) + except (ValueError, TypeError): + return 0.0 + + def format_rate(bps_val): + """Format bits per second to human readable Mbps/Kbps""" + try: + bps = float(bps_val) + if bps >= 1_000_000: + return f"{bps / 1_000_000:.2f} Mbps" + elif bps >= 1_000: + return f"{bps / 1_000:.2f} Kbps" + else: + return f"{bps:.0f} bps" + except (ValueError, TypeError): + return "0 bps" + + # Extract traffic info + traffic_data = [] + for iface in interfaces: + # MikroTik provides tx-bits-per-second and rx-bits-per-second for real-time rate + # For total traffic, it provides tx-byte and rx-byte + tx_bps = iface.get("tx-bits-per-second", iface.get("tx-bit", 0)) + rx_bps = iface.get("rx-bits-per-second", iface.get("rx-bit", 0)) + + traffic_data.append({ + "name": iface.get("name"), + "type": iface.get("type"), + "tx_rate": format_rate(tx_bps), + "rx_rate": format_rate(rx_bps), + "tx_rate_raw_bps": tx_bps, + "rx_rate_raw_bps": rx_bps, + "running": iface.get("running"), + "disabled": iface.get("disabled") + }) + + # Sort by tx_rate descending (highest traffic first) + traffic_data.sort(key=lambda x: float(x.get("tx_rate_raw_bps", 0) or 0), reverse=True) + + snapshot_path = save_snapshot(actual_name, "interface_traffic", traffic_data) + + # Limit display + display_limit = 20 + preview = traffic_data[:display_limit] + + result = { + "router": actual_name, + "filter": "running_only" if running_only else "all", + "total_interfaces": len(traffic_data), + "snapshot_file": snapshot_path, + "interfaces": preview + } + + text_res = json.dumps(result, indent=2) + if len(traffic_data) > display_limit: + text_res += f"\n\n⚠️ Hanya menampilkan {display_limit} dari {len(traffic_data)} interfaces.\n" + text_res += f"📂 Data lengkap: {snapshot_path}" + + return [TextContent(type="text", text=text_res)] + else: raise ValueError(f"Unknown tool: {name}") diff --git a/devices.json b/devices.json index 7e493ed..38b4346 100644 --- a/devices.json +++ b/devices.json @@ -5,5 +5,12 @@ "port": 80, "user": "admin11", "pass": "Dua75316__" + }, + { + "name": "Router-Batuaji", + "host": "10.8.0.15", + "port": 80, + "user": "admin11", + "pass": "Dua75316__" } ] \ No newline at end of file