Skip to main content
Glama

netexpert-mcp

"What's on my network, is my link healthy, is this machine safe, and why is X slow?" — answered by an AI, on your LAN, in one conversation.

netexpert is a cross-platform local-network diagnostics & security-posture MCP server for AI clients (Claude Desktop, Claude Code, or any client that speaks MCP).


Why it exists

Existing network MCP servers are either deprecated Python packages, wrappers that demand Nmap, or router-config tools for enterprises. None of them answer the home-lab questions:

Question

netexpert answer

What devices are on my network — anything new?

lan.devices builds an inventory (ARP ∪ sweep, OUI vendor, PTR hostname); lan.newdevices diffs it against snapshots and emits findings

Is my WiFi actually good?

wifi.health interprets RSSI bands, channel overlap, and band mismatch — with concrete next steps, not raw numbers

Is this machine exposed?

sec.exposure cross-references listening ports with firewall state and a risky-port knowledge base

Is my DNS lying to me?

dns.hijackcheck compares your system resolver against trusted DoH for known-good domains

Why is X unreachable?

Layered triage — link → ARP → routing/DNS → port → app (docs/persona.md)

Related MCP server: Network Ops MCP

Design guarantees

  • One envelope. Every tool returns the same JSON shape (ok, backend, data, warnings / closed-set error.code + actionable hint) — no raw netsh or ip output ever reaches the model.

  • Platform-normalized. Same field names on Windows, Linux, and macOS; platform dispatch lives below the service layer.

  • Bounded everything. Port caps, host caps, byte caps, timeouts, and token-bucket rate limits are enforced in code — never left to the model's judgment.

  • No shell, ever. All subprocesses spawn via arg arrays (execFile-style); all inputs are zod-validated before touching the OS. No raw sockets, no Npcap, no Python.

  • Read-only by default. The one mutating tool (lan.wol) uses a dry-run plan + single-use, 10-min-TTL confirmToken — parameters frozen at plan time.

  • Capability honesty. Tools report which backend produced the data (backend: "tcp-connect", not a fake "ping"); net.health self-describes what works on this host, with install hints for what doesn't.

  • No telemetry. No phone-home — except the three tools that are about the internet (net.publicip, sec.speedtest, DoH in dns.hijackcheck), which you invoked explicitly.

Tool catalog (31)

net.* — connectivity

Tool

What it does

net.health

Version, platform, capability matrix (which backends exist on this host, with install hints)

net.ping

ICMP loss/latency stats; honest TCP-connect fallback when ping is unavailable

net.trace

Traceroute hops, normalized across tracert/traceroute/tracepath

net.httpcheck

GET/HEAD with timing split: dns / connect / ttfb / total

net.portcheck

Single TCP connect — open/closed + latency

net.portscan

Bounded connect scan (≤256 ports, default top-20 common)

net.ssl

TLS cert: subject, SANs, issuer, chain, days-left, expiry grade

net.publicip

Your public IPv4 + ASN/org (ipify → ipinfo fallback)

net.deepscan

Optional nmap adapter — opt-in only: requires the binary and nmap.enabled in config; RFC1918 targets only

dns.* — name resolution

Tool

What it does

dns.lookup

A/AAAA/CNAME/MX/TXT/NS/SRV/PTR with optional nameserver override

dns.reverse

PTR names for an IP

dns.resolvers

Which DNS servers the OS actually uses (per-platform)

dns.propagation

Same record at system + trusted resolvers + DoH — diff table

dns.hijackcheck

The killer check: known-good domains via system vs trusted DoH; mismatch or NXDOMAIN ⇒ Finding{sev:high}

lan.* — devices & inventory

Tool

What it does

lan.interfaces

NICs: name, MAC, addresses, type, virtual flag

lan.gateway

Default gateway + interface + local subnet CIDR

lan.arp

Parsed neighbor cache, stale entries filtered

lan.sweep

Ping-probe an RFC1918 subnet (≤1024 hosts, rate-limited 1/30s) → live set

lan.devices

Inventory: ARP ∩ RFC1918, enriched with vendor (40k-entry IEEE OUI db) + PTR hostname

lan.hostname

All known names for an IP: PTR + NetBIOS (win)

lan.snapshot

Save device inventory to dated snapshots; or list them

lan.newdevices

Diff live vs baseline ⇒ findings (new MAC, MAC-changed-for-IP); first run auto-saves a baseline

lan.wol

Wake-on-LAN magic packet — dry-run plan → confirmToken → one UDP broadcast

wifi.* — link health

Tool

What it does

wifi.status

Current link: SSID, BSSID, band, channel, RSSI, PHY rate, quality 0–100

wifi.networks

Nearby AP survey with band inference

wifi.health

Interpretation: RSSI bands (≥−50 … <−78 unusable), 2.4 GHz channel overlap, band mismatch, low PHY rate — each a Finding with the next tool call

sec.* — host posture

Tool

What it does

sec.connections

Active sockets with owning PID

sec.listening

Listeners per process; flags 0.0.0.0/:: exposures

sec.firewall

Get-NetFirewallProfile / ufw→nft / socketfilterfw

sec.exposure

Headline report: exposed listeners × firewall state × risky-port table (445, 3389, 23, 135–139, 5357, 5900) ⇒ Finding[]

sec.speedtest

Bounded Cloudflare download; reports a lower bound instead of failing on slow links


Getting started

git clone <repo> && cd netexpert-mcp
pnpm install
pnpm build
pnpm smoke        # build → stdio → tools/list → net.health

MCP client config

{ "mcpServers": { "netexpert": { "command": "node", "args": ["<abs-path>/dist/server.js"] } } }

Optional stateless HTTP transport:

NETEXPERT_HTTP_PORT=3100 node dist/server.js
# POST http://127.0.0.1:3100/mcp   (JSON-RPC: tools/list, tools/call)
# GET  http://127.0.0.1:3100/health

Configuration

~/.netexpert-mcp/config.json — sane defaults, so zero-config first run:

{
  "defaults":  { "pingCount": 4, "traceMaxHops": 20 },
  "resolvers": { "trusted": ["1.1.1.1", "8.8.8.8"],
                 "dohUrl": "https://cloudflare-dns.com/dns-query" },
  "caps":      { "portscan": { "maxPorts": 256 }, "sweep": { "maxHosts": 1024 }, "http": {}, "speedtest": {} },
  "rate":      { "sweep": 30, "portscan": 10, "speedtest": 60, "httpCheck": 2 },
  "nmap":      { "enabled": false }   // deep scans are opt-in by design
}

Invariants: caps are ceilings — tool inputs may go lower, never higher. Env overrides via NETEXPERT_* (NETEXPERT_HTTP_PORT, NETEXPERT_MCP_CONFIG). No credentials ever — any config key containing password/token/secret/credential is rejected at load.

The OUI vendor database (src/data/oui.json, 40k IEEE MA-L entries) is committed — never fetched at runtime. Regenerate with node scripts/gen-oui.mjs.

Monitoring without a daemon

netexpert stays request/response; recurring checks are your MCP client's job:

New-device tripwire   lan.newdevices    every 15 min   fire on Finding[] beyond the info baseline
Gateway reachability  net.ping <gw>    every 60 s      fire on lossPct > 0
DNS integrity         dns.hijackcheck   hourly          fire on sev=high
WiFi degradation      wifi.health       every 10 min    fire on severity ≥ med

AI usage — docs/persona.md

The server provides hands; the persona provides judgment. The rule pack in docs/persona.md gives your AI client:

  1. a triage ladder (link → ARP → IP/DNS → port → app — always state which layer exonerated/implicated),

  2. baselines for "suspicious" (new MAC with no vendor match, RFC1918 host on 445/3389 that isn't the NAS, resolver ≠ DoH, ARP flapping),

  3. the Finding format — every answer ends with the concrete next tool call, never a data dump

Project layout

src/
  exec/        LocalExecutor (execFile, arg arrays) + per-platform CommandMaps (win32/linux/darwin)
  parse/       pure parsers (arp, ping, traceroute, netsh, iw, nmap -oG) — fixture-tested
  services/    coreService dnsService lanService wifiService secService nmapService
  safety/      caps.ts (bounds + token-bucket rate limiter) · confirm.ts (dry-run/confirmToken)
  data/        oui.json (40k IEEE OUI entries, committed)
  mcp/         toolset.ts (31 tools, zod inputs) · createServer.ts
scripts/       gen-oui.mjs · smoke.mjs · http-smoke.mjs
docs/          persona.md
tests/         fixtures/ + parsers · services · wifiSec · m4 · nmap (46 tests)
``


License: MIT — see `LICENSE`. Published as [`netexpert-mcp` on npm](https://www.npmjs.com/package/netexpert-mcp).

Related MCP Connectors

Related MCP Servers