# 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 1. **Environment Config** Copy `.env.example` to `.env` and fill in your details: ```bash cp .env.example .env # Edit .env ``` 2. **Bootstrap Elastic** Run the bootstrap script (requires `requests` installed locally, or you can run it inside a container): ```bash python3 scripts/bootstrap_indices.py ``` *Note: Ensure you have connectivity to your Elasticsearch instance.* 3. **Start Services** ```bash docker-compose up -d --build ``` This brings up the collectors and the lightweight frontend (reachable on port `5001`). ## Configuration - **Static Metadata**: Edit `static/host_metadata.json` to add manual notes, roles, or tags to hosts (keyed by `mac:xx:xx...`). - **Intervals**: Adjust polling intervals in `.env`. - **VLAN Discovery (default on)**: Discovery sweeps (`nmap -sn`) run periodically across the OPNsense interfaces listed in `NMAP_DISCOVERY_VLANS`. Adjust the list (or set the flag to `false`) 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 per `NMAP_FULL_INTERVAL_SECONDS` (default daily). Tune these env vars to balance coverage vs. runtime. - **Inventory Overlay**: Entries in `./inventory_targets.yml` are mounted into the OPNsense collector and merged by IP—offline/static hosts from that file (names, notes, expected ports) now appear in `network-hosts` with `source: 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: ```json 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: ```bash docker-compose up -d frontend ``` Then visit `http://: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: ```bash 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 (supports `limit`, `source`, and repeated `q` params to fuzzy search names, hostnames, IPs, or MACs in a single call). - `GET /api/hosts/` – single host document with optional `include_events=true`. - `GET /api/events` – recent scan/discovery events (`limit`, `host_id`, `type`, `since` filters). - `GET /api/hosts//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 optional `include_events`, `events_limit`. - `list_events` – `{limit, host_id, type, since}`. - `host_events` – requires `{host_id}` plus optional `limit`, `type`, `since`. Resource URI examples: - `network://hosts?q=seele&limit=50` - `network://host/mac:dc:a6:32:67:55:dc?include_events=true&events_limit=50` - `network://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: ```bash codex mcp install network-mcp http://:5001/.well-known/mcp.json ```