Network MCP
A "source of truth" for network devices and ports, backed by Elasticsearch, OPNsense, and Nmap.
Architecture
- Elasticsearch: Stores current state (
network-hosts) and historical events (network-events-*). - OPNsense Collector: Fetches DHCP/ARP/DNS data to discover hosts.
- Nmap Collector: Scans discovered hosts for open ports and OS info.
Setup
-
Environment Config Copy
.env.exampleto.envand fill in your details:cp .env.example .env # Edit .env -
Bootstrap Elastic Run the bootstrap script (requires
requestsinstalled locally, or you can run it inside a container):python3 scripts/bootstrap_indices.pyNote: Ensure you have connectivity to your Elasticsearch instance.
-
Start Services
docker-compose up -d --buildThis brings up the collectors and the lightweight frontend (reachable on port
5001).
Configuration
- Static Metadata: Edit
static/host_metadata.jsonto add manual notes, roles, or tags to hosts (keyed bymac:xx:xx...). - Intervals: Adjust polling intervals in
.env. - VLAN Discovery (default on): Discovery sweeps (
nmap -sn) run periodically across the OPNsense interfaces listed inNMAP_DISCOVERY_VLANS. Adjust the list (or set the flag tofalse) if you only want targeted subnets. - Quick vs Full Port Scans: Each collector loop runs a fast, common-port sweep (
NMAP_QUICK_EXTRA_ARGS,NMAP_QUICK_BATCH_SIZE) while a deeper service scan (NMAP_PORT_RANGE,NMAP_BATCH_SIZE) is triggered once perNMAP_FULL_INTERVAL_SECONDS(default daily). Tune these env vars to balance coverage vs. runtime. - Inventory Overlay: Entries in
./inventory_targets.ymlare mounted into the OPNsense collector and merged by IP—offline/static hosts from that file (names, notes, expected ports) now appear innetwork-hostswithsource: inventory.
Data Model
network-hosts: Current state of every known host.network-events-YYYY.MM.DD: Immutable log of scans and discovery events.
Usage
Query network-hosts for the latest view of your network:
GET network-hosts/_search
{
"query": {
"match_all": {}
}
}
Quick Frontend
A minimal Flask frontend is bundled in docker-compose (service frontend) and is exposed on port 5001 so it can be reached from other machines:
docker-compose up -d frontend
Then visit http://<host-ip>:5001/ to see the merged view (inventory entries are marked with source: inventory). If you prefer to run it without Docker for debugging, follow the steps below:
cd network-mcp
python3 -m venv .venv && source .venv/bin/activate
pip install -r frontend/requirements.txt
python frontend/app.py
MCP / API Endpoints
The frontend doubles as a Model Context Protocol server. It exposes the manifest at /.well-known/mcp.json (or /api/mcp) and supports the standard JSON-RPC handshake (initialize, tools/list, tools/call) on the same URL. Agents can either use the RPC tools below or hit the underlying REST endpoints directly.
-
MCP Resources are also available (
resources/list,resources/read,resources/templates/list) for clients that prefer resource-style access to snapshots and queries. -
GET /api/hosts– merged host list (supportslimit,source, and repeatedqparams to fuzzy search names, hostnames, IPs, or MACs in a single call). -
GET /api/hosts/<host_id>– single host document with optionalinclude_events=true. -
GET /api/events– recent scan/discovery events (limit,host_id,type,sincefilters). -
GET /api/hosts/<host_id>/events– scoped events for a host. -
GET /api/map– high-level “network map” grouping hosts by detected /24 (IPv4) or /64 (IPv6).
RPC tool names (mirrored in the manifest) are:
list_hosts– accepts{limit, source, terms}and returns the merged host list.network_map– optional{limit}for building /24-/64 summaries.get_host– requires{host_id}plus optionalinclude_events,events_limit.list_events–{limit, host_id, type, since}.host_events– requires{host_id}plus optionallimit,type,since.
Resource URI examples:
network://hosts?q=seele&limit=50network://host/mac:dc:a6:32:67:55:dc?include_events=true&events_limit=50network://events?type=discovery&limit=100
All RPC and REST calls share the Elasticsearch credentials from .env, so an agent only needs HTTP access to port 5001 to query hosts, notes, and event timelines. Registering the MCP with Codex looks like:
codex mcp install network-mcp http://<host>:5001/.well-known/mcp.json