LLMs can explain Linux networking concepts well enough, but out of the box they have no visibility into a live machine. They cannot see your network interfaces, tell you if a WireGuard tunnel has an MTU mismatch or check if an adapter is dropping packets.
Anthropic's Model Context Protocol (MCP) is a practical way to bridge that. It gives you a standard interface for exposing local or remote tools to clients like Claude Desktop, Cursor, or your own agents.
In this post, we will build an async Python MCP server—alongside a FastAPI REST endpoint—that reads live Linux network interface metrics (eth0, wlan0, tun0, wg0), structures the output with Pydantic v2, and flags a couple of common network misconfigurations.
Prerequisites
- Python 3.12+ and
uvinstalled - A Linux environment (Ubuntu, Debian, or WSL2)
Step 1: Bootstrap the Project with uv
Create a new project directory and install the mcp SDK along with psutil, pydantic, and fastapi:
mkdir netpulse-mcp && cd netpulse-mcp uv init --python 3.12 uv add "mcp[cli]" fastapi "uvicorn[standard]" pydantic psutil Step 2: Define Typed Telemetry Schemas with Pydantic v2
If you pipe raw shell output like ifconfig directly into an LLM, you waste context tokens and risk the model misreading the text. Returning a strict Pydantic model is much cleaner because both REST clients and MCP tool calls get a predictable JSON structure.
Create main.py and set up the models:
from typing import Dict, List, Optional import psutil from fastapi import FastAPI from pydantic import BaseModel, Field from mcp.server.fastmcp import FastMCP mcp = FastMCP("NetPulse Linux Network Diagnostics") app = FastAPI(title="NetPulse Diagnostics API", version="0.1.0") class InterfaceStats(BaseModel): name: str is_up: bool mtu: int bytes_sent: int bytes_recv: int packets_dropped: int = Field(description="Total inbound and outbound dropped packets") anomaly_detected: bool = False diagnostic_note: Optional[str] = None class SystemNetworkReport(BaseModel): hostname_interfaces: List[InterfaceStats] healthy: bool Step 3: Implement the Linux Interface Inspector
Now we can add the diagnostic logic to main.py. We will use psutil.net_if_stats() and psutil.net_io_counters() to read the kernel interface counters and run two basic checks:
- Flag any interface with more than 100 total packet drops (
dropin + dropout). - Flag virtual tunnel interfaces (
tun*,wg*) with an MTU above1420, since that often causes packet fragmentation over encapsulated links.
async def collect_interface_diagnostics() -> SystemNetworkReport: stats = psutil.net_if_stats() io_counters = psutil.net_io_counters(pernic=True) results: List[InterfaceStats] = [] system_healthy = True for iface, iface_stat in stats.items(): io = io_counters.get(iface) if not io: continue dropped = io.dropin + io.dropout anomaly = False note = "OK" if dropped > 100: anomaly = True system_healthy = False note = f"High packet drop count ({dropped}). Check ring buffers (ethtool -g) or qdisc." elif iface.startswith(("tun", "wg")) and iface_stat.mtu > 1420: anomaly = True note = f"Suboptimal tunnel MTU ({iface_stat.mtu}). Consider clamping to 1420 or 1280 for IPv6." results.append( InterfaceStats( name=iface, is_up=iface_stat.isup, mtu=iface_stat.mtu, bytes_sent=io.bytes_sent, bytes_recv=io.bytes_recv, packets_dropped=dropped, anomaly_detected=anomaly, diagnostic_note=note, ) ) return SystemNetworkReport(hostname_interfaces=results, healthy=system_healthy) Step 4: Expose the Function to MCP and FastAPI
FastMCP uses your Python type hints and docstring to build the JSON-RPC tool definition automatically when you add the @mcp.tool() decorator. We can also wire the exact same function up to a FastAPI route:
@mcp.tool() async def diagnose_linux_network() -> Dict: """Inspects all Linux network interfaces (including TUN/TAP and WireGuard), MTU settings, and packet drops.""" report = await collect_interface_diagnostics() return report.model_dump() @app.get("/api/v1/diagnostics", response_model=SystemNetworkReport) async def get_diagnostics(): return await collect_interface_diagnostics() if __name__ == "__main__": mcp.run() Step 5: Test the Server Locally
To test the tool interactively, run the MCP Inspector:
uv run mcp dev main.py Or start uvicorn and hit the FastAPI endpoint with curl:
uv run uvicorn main:app --port 8000 & curl -s http://localhost:8000/api/v1/diagnostics | python3 -m json.tool Exposing read-only telemetry like this gives an AI assistant enough context to spot network issues on a host without giving it raw shell access.