2025-12-31 20:11:44 -05:00

106 lines
4.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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://<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:
```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/<host_id>` single host document with optional `include_events=true`.
- `GET /api/events` recent scan/discovery events (`limit`, `host_id`, `type`, `since` filters).
- `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 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://<host>:5001/.well-known/mcp.json
```