User Guide
Enterprise Deployment & Configuration Reference
Version 1.0  ·  February 2026
Covers: Collection · Ingestion · Query API · Web UI · MCP Server
meshoptixiq.com  ·  hello@meshoptixiq.com
Proprietary & Confidential
Chapter 1

Introduction & Architecture

1.1 Product Overview

MeshOptixIQ is a vendor-agnostic network intelligence platform that collects live operational state from network devices, normalises it into a canonical graph model, and exposes the resulting topology for query, visualisation, and AI-assisted reasoning.

Rather than scraping device CLIs for ad-hoc troubleshooting, MeshOptixIQ builds a persistent, queryable model of your network — one that supports blast-radius analysis, endpoint hunting, IP-addressing audits, and firewall policy review without requiring manual correlation across multiple management systems.

Who Should Read This Guide

This guide is written for network engineers, systems administrators, and DevOps teams deploying MeshOptixIQ in production environments. Familiarity with Linux system administration, SSH, and basic IP networking concepts is assumed.

1.2 Key Capabilities

Topology Graph

  • Automatic neighbour discovery via CDP/LLDP data
  • Interface-level connection mapping
  • Interactive Cytoscape.js topology viewer
  • Full-text device and interface search

Endpoint Intelligence

  • Locate hosts by IP or MAC address
  • Trace physical path to upstream switch port
  • ARP/MAC table correlation across vendors

Blast Radius Analysis

  • Impact scope for device, interface, VLAN, or subnet outage
  • Endpoint count and list per scenario
  • Pre-maintenance change impact report

Firewall Policy Intelligence

  • Collect security policies from PAN-OS, JunOS, FortiOS, ASA
  • Zone-pair rule analysis
  • Source-to-destination path analysis with permit/deny verdict

1.3 System Architecture

MeshOptixIQ is composed of four logical layers:

  1. Collection layermeshq collect connects to devices over SSH using Netmiko, retrieves CLI output, and writes raw text to a local cache directory.
  2. Normalisation layermeshq parse reads the raw cache and produces vendor-agnostic Pydantic models (devices, interfaces, IPs, MACs, VLANs, endpoints, firewall rules, address objects, service objects).
  3. Graph layermeshq ingest writes the normalised models into Neo4j or PostgreSQL. The graph schema represents devices as nodes, connections as relationships, and all other facts as node properties or related nodes.
  4. Query layer — A FastAPI service exposes 23 named queries via /queries/. The same queries are available via the MCP server (meshq-mcp) for AI-assistant integration. A React/Vite single-page application provides the web interface.
  ┌──────────────────────────────────────────────────────┐
  │  Network Devices  (SSH / Netmiko)                   │
  └──────────────┬───────────────────────────────────────┘
                 │ raw CLI text
  ┌──────────────▼───────────────────────────────────────┐
  │  meshq collect → local cache (~/.meshoptixiq/cache/) │
  └──────────────┬───────────────────────────────────────┘
                 │ parsed models (Pydantic)
  ┌──────────────▼───────────────────────────────────────┐
  │  meshq parse → meshq ingest → Neo4j / PostgreSQL     │
  └──────────────┬───────────────────────────────────────┘
                 │ Cypher / SQL queries
  ┌──────────────▼──────────────┬────────────────────────┐
  │  FastAPI Query API          │  MCP Server (stdio)    │
  │  /queries/*  :8000          │  meshq-mcp             │
  └──────────────┬──────────────┴────────────────────────┘
                 │
  ┌──────────────▼───────────────────────────────────────┐
  │  React Web UI  (served by FastAPI at /static)        │
  └──────────────────────────────────────────────────────┘

1.4 License Plans

FeatureCommunityStarterProEnterprise
Installations115Unlimited
Network devices scanned1100750Unlimited
Query API & Web UIWeb UI only
POST /queries/*/execute403403
MCP Server (meshq-mcp)
Firewall queries
What-if simulation
NetBox sync
Redis clustering
RBAC access control
PostgreSQL backend
Data export (CSV / Ansible)
Audit logging
OIDC/SSO
SOAR webhooks
Custom parsers
SupportCommunityCommunityEmailDedicated
Query Execution Gating
Community and Starter plans receive HTTP 403 Forbidden on POST /queries/{name}/execute. Only Pro and Enterprise plans may execute queries. Use the demo mode (MESHOPTIXIQ_DEMO_MODE=true) for evaluation without a license.
72-Hour Grace Period
If the licensing server is unreachable, MeshOptixIQ continues operating for 72 hours. Connectivity is checked every 24 hours; the grace period resets on successful validation.
Chapter 2

System Requirements

2.1 Host Requirements

ComponentMinimumRecommended
OSLinux (kernel 4.x+), macOS 12+Ubuntu 22.04 LTS or RHEL 9
CPU2 cores4 cores
RAM4 GB8 GB (16 GB for large networks)
Disk20 GB100 GB SSD (for raw cache + DB)
Python3.103.12
Docker24.0 (if using containers)25.0+

2.2 Database Requirements

Neo4j (Default)

TierVersionEditionNotes
Development5.xCommunity EditionFree; single instance only
Production5.xCommunity or Aura FreeNeo4j Aura provides managed cloud hosting
Enterprise5.xEnterprise EditionRequired for clustering & advanced auth

Neo4j must be reachable over the Bolt protocol (default port 7687). HTTP/HTTPS (7474) is optional and used only for the Neo4j Browser UI.

PostgreSQL (Pro/Enterprise Alternative)

PostgreSQL 14 or later. The psycopg v3 driver (psycopg[binary]) is required. Install the postgres extras: pip install "meshoptixiq-network-discovery[postgres]".

2.3 Network Requirements

DirectionPort / ProtocolPurpose
MeshOptixIQ host → Network devicesTCP 22 (SSH)Device collection via Netmiko
MeshOptixIQ host → Neo4jTCP 7687 (Bolt)Graph database reads/writes
MeshOptixIQ host → PostgreSQLTCP 5432Alternate graph backend
MeshOptixIQ host → InternetTCP 443 (HTTPS)License validation (api.meshoptixiq.com)
Client browsers → MeshOptixIQ hostTCP 8000Query API & Web UI
Firewall Note
Outbound HTTPS to api.meshoptixiq.com is required for initial license validation. If the host is air-gapped, the 72-hour grace period applies on first startup. Contact hello@meshoptixiq.com for extended offline licensing options.
Chapter 3

Installation

3.1 Docker Installation (Recommended)

The official Docker image bundles the FastAPI query API, the React web UI, and the Cython-compiled licensing module. It is the fastest path to a working deployment.

Step 1 — Pull the Image

docker pull meshoptixiq/discovery-agent:latest

Step 2 — Start Neo4j

docker run -d \
  --name neo4j \
  -p 7687:7687 -p 7474:7474 \
  -e NEO4J_AUTH=neo4j/your-password \
  -v neo4j-data:/data \
  neo4j:5-community

Step 3 — Start MeshOptixIQ

docker run -d \
  --name meshoptixiq \
  -p 8000:8000 \
  --link neo4j:neo4j \
  -e GRAPH_BACKEND=neo4j \
  -e NEO4J_URI=bolt://neo4j:7687 \
  -e NEO4J_USER=neo4j \
  -e NEO4J_PASSWORD=your-password \
  -e MESHOPTIXIQ_LICENSE_KEY=mq-prod-xxxxxxxxxx \
  -e API_KEY=your-api-key-here \
  -v meshoptixiq-cache:/app/cache \
  meshoptixiq/discovery-agent:latest

Step 4 — Verify

curl http://localhost:8000/health
# {"status":"ok"}

curl http://localhost:8000/health/ready
# {"status":"ok","backend":"neo4j"}
Docker Compose
For production deployments with a complete stack including Neo4j, a reverse proxy, and automatic restarts, see Chapter 10 — Advanced Deployment.

3.2 Python Package Installation

Install directly from PyPI for environments where Docker is not available or for development use.

Base Installation

pip install meshoptixiq-network-discovery

With PostgreSQL Support

pip install "meshoptixiq-network-discovery[postgres]"

With MCP Server

pip install "meshoptixiq-network-discovery[mcp]"

Full Installation (All Extras)

pip install "meshoptixiq-network-discovery[postgres,mcp]"
Python Version
Python 3.10 or later is required. Python 3.12 is recommended for best performance. Virtual environments (python -m venv .venv) are strongly recommended.

Verify CLI Installation

meshq version
# MeshOptixIQ Network Discovery v1.0.0
# License: Pro (Expires: 2027-12-31)

3.3 License Activation

MeshOptixIQ requires a valid license key for all operations beyond basic collection. Keys are issued at meshoptixiq.com/pricing and take the form mq-prod-xxxxxxxxxx.

Method A — Environment Variable (Recommended for Docker)

export MESHOPTIXIQ_LICENSE_KEY="mq-prod-xxxxxxxxxx"

Pass this to Docker with -e MESHOPTIXIQ_LICENSE_KEY or include it in a .env file with Docker Compose.

Method B — License File (Recommended for Bare-Metal)

mkdir -p ~/.meshoptixiq
echo "mq-prod-xxxxxxxxxx" > ~/.meshoptixiq/license.key
chmod 600 ~/.meshoptixiq/license.key

The application checks the file path ~/.meshoptixiq/license.key on startup; the environment variable takes precedence if both are present.

Security Warning
Never commit license keys to version control. Use a secrets manager (AWS Secrets Manager, HashiCorp Vault, Docker Secrets) for production deployments.

Device Registration

On first startup, MeshOptixIQ registers the host device fingerprint (based on hostname, MAC address, and CPU architecture) with the licensing server. Pro licenses support up to 5 registered devices; Enterprise licenses are unlimited.

3.4 Verifying the Installation

  1. Check the CLI version and license status: meshq version
  2. Verify database connectivity: curl http://localhost:8000/health/ready
  3. List available queries: curl -H "X-API-Key: $API_KEY" http://localhost:8000/queries/
  4. Open the web UI: navigate to http://localhost:8000 in a browser

A successful installation shows 25 queries in the API response and the topology graph in the web UI (empty until data is collected).

Chapter 4

Configuration

4.1 Environment Variables

All configuration is driven by environment variables. No configuration files are required. See Appendix A for the complete reference; the most critical variables are listed below.

VariableRequiredDefaultDescription
MESHOPTIXIQ_LICENSE_KEYRequiredLicense key from the customer portal
GRAPH_BACKENDOptionalneo4jneo4j or postgres
NEO4J_URIIf Neo4jbolt://localhost:7687Neo4j Bolt connection URI
NEO4J_USERIf Neo4jneo4jNeo4j username
NEO4J_PASSWORDRequiredNeo4j password
POSTGRES_DSNPro+Full PostgreSQL DSN (if using postgres backend)
API_KEYRequiredShared secret for API authentication. The server will not start without this set.
CORS_ORIGINSOptionalComma-separated list of allowed CORS origins. Defaults to empty (all cross-origin requests denied).
UI_DIROptional/app/staticPath to the compiled React app; set to an empty path to disable the web UI
MCP_MAX_RESULT_ROWSOptional1000Global row cap per MCP tool call

4.2 Neo4j Backend Configuration

Connection String Formats

# Local bolt (default)
NEO4J_URI=bolt://localhost:7687

# TLS-encrypted bolt
NEO4J_URI=bolt+s://neo4j.internal:7687

# Aura cloud (always TLS)
NEO4J_URI=neo4j+s://xxxxxxxx.databases.neo4j.io

Schema Initialisation

On first ingest, MeshOptixIQ creates uniqueness constraints and indexes automatically. To apply constraints manually (recommended before bulk ingest):

meshq ingest --init-schema

Performance Tuning

For networks with more than 200 devices, increase Neo4j heap allocation in neo4j.conf:

dbms.memory.heap.initial_size=1G
dbms.memory.heap.max_size=4G
dbms.memory.pagecache.size=2G

4.3 PostgreSQL Backend Configuration

The PostgreSQL backend stores topology data in relational tables with array columns for multi-value fields (zones, addresses, services in firewall rules). It is functionally equivalent to the Neo4j backend for all 25 queries.

export GRAPH_BACKEND=postgres
export POSTGRES_DSN="postgresql://meshoptixiq:password@db.internal:5432/meshoptixiq"

Schema Creation

The schema is applied automatically on first ingest. Tables created include: devices, interfaces, ip_addresses, subnets, vlans, mac_addresses, endpoints, firewall_rules, address_objects, service_objects.

When to Use PostgreSQL
Choose PostgreSQL when you need SQL-native reporting, integration with existing BI tools, or when your team is more comfortable with relational databases. Neo4j provides superior performance for deeply recursive graph traversal queries (blast radius, path analysis).

4.4 API Authentication

The Query API uses a shared API key passed in the X-API-Key HTTP header. API_KEY is required — the server will exit at startup if it is not set.

# Set a strong random key (32+ characters)
export API_KEY=$(openssl rand -hex 32)

# All API requests must include the header
curl -H "X-API-Key: $API_KEY" http://localhost:8000/queries/

CORS Configuration

Restrict CORS to your specific UI origin in production:

export CORS_ORIGINS="https://meshoptixiq.yourdomain.com,https://admin.yourdomain.com"
Chapter 5

Network Device Collection

MeshOptixIQ collects operational state from network devices using SSH. The collection pipeline has three stages: collect (raw CLI output), parse (normalise to models), and ingest (write to the graph).

5.1 Supported Vendors & OS Types

VendorOS / PlatformFacts Collected
CiscoIOS / IOS-XEInterfaces, IPs, ARP, MAC table, VLANs, neighbors (CDP)
AristaEOSInterfaces, IPs, ARP, MAC table, neighbors (LLDP)
JuniperJunOSInterfaces, IPs, ARP, neighbors (LLDP), security policies, address objects
ArubaArubaOSInterfaces, IPs, ARP, MAC table, VLANs
Palo AltoPAN-OSInterfaces, ARP, system info, security policies, address/service objects
FortinetFortiOSSecurity policies, address objects
CiscoASA OSACLs (access-lists), object-groups
Custom Parsers
Enterprise plans support custom vendor parsers. Contact hello@meshoptixiq.com to discuss integration of additional vendors or OS versions.

5.2 Inventory File Format

Devices are defined in a YAML inventory file. By convention this file is named inventory.yaml and stored in the project directory.

devices:
  # Cisco IOS core switch
  - hostname: sw-core-01
    host: 10.0.0.1
    device_type: cisco_ios
    username: netops
    password: "{{ env.SWITCH_PASSWORD }}"
    port: 22
    timeout: 30

  # Arista EOS distribution switch
  - hostname: sw-dist-01
    host: 10.0.0.2
    device_type: arista_eos
    username: netops
    password: "{{ env.SWITCH_PASSWORD }}"

  # PAN-OS firewall (includes firewall policy collection)
  - hostname: fw-edge-01
    host: 10.0.0.10
    device_type: paloalto_panos
    username: admin
    password: "{{ env.FW_PASSWORD }}"

  # Juniper SRX firewall
  - hostname: fw-srx-01
    host: 10.0.0.11
    device_type: juniper_junos
    username: netops
    password: "{{ env.FW_PASSWORD }}"

  # Fortinet FortiGate
  - hostname: fw-fg-01
    host: 10.0.0.12
    device_type: fortinet
    username: admin
    password: "{{ env.FW_PASSWORD }}"

  # Cisco ASA
  - hostname: fw-asa-01
    host: 10.0.0.13
    device_type: cisco_asa
    username: cisco
    password: "{{ env.FW_PASSWORD }}"

Supported device_type Values

device_typeVendor / OS
cisco_iosCisco IOS, IOS-XE
arista_eosArista EOS
juniper_junosJuniper JunOS (MX, EX, SRX)
aruba_osAruba ArubaOS
paloalto_panosPalo Alto PAN-OS
fortinetFortinet FortiOS
cisco_asaCisco ASA

Credential Security

Never store credentials in plain text in inventory files. Use environment variable references ({{ env.VAR_NAME }}) or a secrets manager. For Docker deployments, use Docker Secrets or pass credentials via environment variables.

5.3 Running Collection

Collect Raw Data

# Collect from all devices in the inventory file
meshq collect --source inventory.yaml

# Collect from a specific device (by hostname)
meshq collect --source inventory.yaml --device sw-core-01

# Collect with a higher timeout (seconds, default 30)
meshq collect --source inventory.yaml --timeout 60

# Run in parallel (default 4 workers; increase for large networks)
meshq collect --source inventory.yaml --workers 8

Raw CLI output is saved to ~/.meshoptixiq/cache/<hostname>/. Each collection run overwrites the previous cache for that device.

SSH Key Authentication
To use SSH key authentication instead of passwords, set use_keys: true and key_file: /path/to/key.pem in the device definition, or configure SSH agent forwarding.

Check Collection Status

meshq status
# Shows last collection time, device count, and any collection errors

Scheduling Regular Collection

For continuous network intelligence, schedule collection with cron or a container orchestrator:

# Cron example — collect every 4 hours
0 */4 * * * /usr/local/bin/meshq collect --source /opt/meshoptixiq/inventory.yaml \
  && /usr/local/bin/meshq parse \
  && /usr/local/bin/meshq ingest

5.4 Parsing and Ingestion

Parse Cached Data

# Parse all cached device data
meshq parse

# Parse a specific device only
meshq parse --device sw-core-01

Parsing produces normalised Pydantic models and reports counts: devices, interfaces, IPs, MACs, VLANs, endpoints. Parsing errors are reported per-device and do not abort the run.

Ingest into Graph

# Ingest parsed data into the configured graph backend
meshq ingest

# Ingest and reinitialise schema constraints first
meshq ingest --init-schema

# Ingest from a specific parsed file
meshq ingest --file /path/to/facts.json

One-Command Pipeline

# Collect, parse, and ingest in sequence
meshq collect --source inventory.yaml \
  && meshq parse \
  && meshq ingest

Verifying Ingested Data

# Check summary counts via the API
curl -H "X-API-Key: $API_KEY" \
  http://localhost:8000/queries/summary_stats/execute \
  -H "Content-Type: application/json" \
  -d '{"parameters": {}}'

# Expected response
{
  "total": 1,
  "rows": [{
    "device_count": 12,
    "interface_count": 247,
    "endpoint_count": 1843,
    "vlan_count": 18
  }]
}
Chapter 6

Firewall Policy Collection

MeshOptixIQ extends its collection pipeline to gather security policies directly from firewalls. Collected rules are stored in the graph alongside topology data, enabling zone-pair queries and source-to-destination path analysis.

6.1 Supported Firewall Vendors

VendorOSFacts Collected
Palo Alto NetworksPAN-OSSecurity policies, address objects, service objects
JuniperJunOS SRXSecurity policies (zone-based), address book objects
FortinetFortiOSFirewall policies, address objects, address groups
CiscoASA OSAccess-lists (ACLs), object-groups
CiscoFirepower FTD (LINA)Access-lists (ASA-compatible LINA format), object-groups
Check PointGaia ClishRule base (best-effort SSH via show rule-base)

Graph Nodes Created

Node TypeKey PropertiesRelationship
FirewallRulerule_id, rule_name, action, rule_order, source/dest zones & addressesDevice HAS_FIREWALL_RULE
AddressObjectname, type (host/network/range/fqdn/group), valueDevice HAS_ADDRESS_OBJECT
ServiceObjectname, protocol, dest_portsDevice HAS_SERVICE_OBJECT

6.2 Collection Workflow

Firewall collection uses the same inventory file as topology collection. Ensure firewall devices are listed with the correct device_type (paloalto_panos, juniper_junos, fortinet, cisco_asa, cisco_ftd, or checkpoint_gaia).

# Collect all devices including firewalls
meshq collect --source inventory.yaml

# Parse — automatically detects and processes firewall output
meshq parse

# Ingest — writes FirewallRule, AddressObject, ServiceObject nodes
meshq ingest

Verifying Firewall Data

# List all firewalls with collected rules
curl -H "X-API-Key: $API_KEY" \
  http://localhost:8000/queries/all_firewall_devices/execute \
  -d '{"parameters": {}}'

# Get rules for a specific device
curl -H "X-API-Key: $API_KEY" \
  http://localhost:8000/queries/firewall_rules_by_device/execute \
  -d '{"parameters": {"device": "fw-edge-01"}}'

Deny Rules Summary

curl -H "X-API-Key: $API_KEY" \
  http://localhost:8000/queries/deny_rules_summary/execute \
  -d '{"parameters": {}}'

6.3 Path Analysis

Path analysis evaluates firewall rules for a given source IP, destination IP, and optional protocol/port. The query returns the first-matching rule per firewall along the path; firewalls with no matching rule are treated as implicit default-deny.

# Check if TCP/443 is permitted: 10.0.0.1 → 10.1.0.100
curl -H "X-API-Key: $API_KEY" \
  http://localhost:8000/queries/path_analysis/execute \
  -H "Content-Type: application/json" \
  -d '{
    "parameters": {
      "source_ip": "10.0.0.1",
      "destination_ip": "10.1.0.100",
      "protocol": "tcp",
      "destination_port": "443"
    }
  }'

The response includes the matching rule for each firewall, its action (permit/deny/drop), rule name, and zone pair. Use the Path Analysis page in the web UI for an interactive view with a PERMITTED / DENIED verdict banner.

Advanced Query Gate
Path analysis and zone-pair queries require a Pro or Enterprise license with the advanced_queries feature enabled.
Chapter 7

Web Interface

The MeshOptixIQ web interface is a React/TypeScript single-page application built with Vite, Tailwind CSS, TanStack Query, and Cytoscape.js. It is served by the FastAPI process at port 8000 and requires no separate deployment. Navigate to http://<host>:8000 after the container starts.

User Access Levels

Personas are access levels that control which pages and features are available to you in the web interface. Each persona unlocks a progressively larger part of the application, so you only see what is relevant to your role.

PersonaTypical RolePages Available
helpdeskSupport staff, help deskDashboard, Topology, Devices, Endpoints, Blast Radius, Change Center
analystIT analysts, NOC operatorsAll of the above + Subnets & IP Schema, Query Workbench
securitySecurity engineersAll of the above + Firewall Policies, Path Analysis
networkNetwork engineersAll of the above + Automation, Collection
architectSenior / principal engineersSame as network
adminAdministratorsFull access, including the Admin page

Your current persona is shown as a badge in the User menu at the top-right of every page. In the default single-user setup (API key authentication), you automatically receive the admin persona and have full access to every page. If your organisation has configured role-based access control Pro+, your persona is determined by the roles or groups assigned to your account — contact your administrator if you cannot reach a page you expect to see.

The table below lists every page in the web interface along with the minimum persona required to access it.

RoutePageMinimum Persona
/DashboardAll
/topologyTopologyAll
/devicesDevice InventoryAll
/endpointsEndpoint SearchAll
/subnetsSubnets & IP Schemaanalyst
/firewallFirewall Policiessecurity
/path-analysisPath Analysissecurity
/blast-radiusBlast RadiusAll
/historyChange CenterAll
/automationAutomationnetwork
/collectionCollectionnetwork
/queriesQuery Workbenchanalyst
/adminAdminadmin
Settings redirect
/settings permanently redirects to /admin for backwards compatibility with bookmarks.

Dashboard (/)

The Dashboard is the home page you see when you open the web interface. It gives you an at-a-glance overview of the current state of your network:

  • Network summary — counts of collected devices, interfaces, IP addresses, endpoints, VLANs, and firewall rules updated every few minutes.
  • Security posture panel — hygiene indicators showing devices without neighbours, interfaces without IPs, and endpoints without subnet assignments. Each indicator is a shortcut to the relevant detail page.
  • Network mini-map — a compact thumbnail of the topology graph so you can spot changes at a glance without switching to the full Topology view.
  • Live activity badge — the status bar at the top shows whether the server is reachable and whether real-time updates are streaming.

The Dashboard does not require any specific persona — it is available to every user regardless of access level.

7.1 App Shell & Navigation

Top Bar

A fixed bar at the top of every page provides at-a-glance status and global shortcuts:

  • Global search button — click to open the Command Palette (or press Cmd+K / Ctrl+K from anywhere)
  • Backend health dot — green (reachable), amber (degraded), red (unreachable); the label reads "Live" or "Offline" so colour-blind users are not excluded
  • Live / Polling badge — "Live" when real-time push updates are active; "Polling" when the interface falls back to checking for updates every 30 seconds
  • Demo badge — an amber "DEMO" label shown when the server is running in demonstration mode with simulated data
  • Notifications bell — count of recent toast events; click to review the list
  • User menu — current persona badge; Disconnect / Clear session

Command Palette (Cmd+K / Ctrl+K)

Press Cmd+K on macOS or Ctrl+K on Windows/Linux from any page to open the Command Palette. It provides smart routing based on what you type:

InputAction
IP address (e.g. 10.0.1.55)Navigate to Endpoint Search with the IP pre-filled and the search fired
CIDR (e.g. 10.0.0.0/24)Navigate to Endpoint Search in subnet mode
MAC address fragmentNavigate to Endpoint Search in MAC mode
Hostname fragment (e.g. core-sw)Navigate to Topology and focus the matching device
Page name (e.g. firewall, topology)Jump directly to that page
Reload RBACForce an immediate reload of the access control policy — useful after an administrator has edited the RBAC policy file without restarting the server admin

Inspector Drawer

The right-side Inspector Drawer slides in when you click a device row in Device Inventory, a node in the Topology graph, or a rule row in Firewall Policies. It persists across page navigation until explicitly closed (× button or Escape).

For devices, the drawer shows six tabs:

TabContents
SummaryHostname, vendor, model, serial, OS version, and NetBox metadata (site / tenant / rack) if present
InterfacesAll interfaces with IP addresses and link state
NeighborsCDP/LLDP-discovered neighbours; click "View" to focus the neighbour in Topology
EndpointsHosts learned on each interface via ARP and MAC tables
FirewallCollected security rules (if any); empty state for non-firewall devices
HistorySnapshots in which this device appears, with timestamps

Sidebar Navigation Groups

The left sidebar organises pages into seven sections:

SectionPages
OverviewDashboard
ObserveTopology, Path Analysis
AssetsDevices, Endpoints, Subnets
SecurityFirewall Policies, Blast Radius
OperationsChange Center, Automation, Collection
WorkbenchQuery Workbench
SystemAdmin

7.2 Topology View (/topology)

The topology view renders a Cytoscape.js force-directed graph of all network devices and their connections.

Node Types & Colours

Node Shape / ColourDevice Type
Blue circleStandard network device (switch, router)
Orange diamondFirewall device (has at least one collected firewall rule)
Rose / red highlightDevice impacted by a Blast Radius overlay
Emerald / green highlightDevice in an active Path Analysis overlay

Interactions

  • Click a node — opens the Inspector Drawer with the 6-tab device detail panel.
  • Click an edge — shows the interfaces on each end that form the connection.
  • Scroll / pinch — zoom the graph.
  • Drag — pan the canvas or reposition nodes.
  • Search bar — filters the graph by hostname; entering a name in focus mode triggers a 2-hop neighbourhood query.

Focus Mode (large networks)

When the graph contains more than 200 devices a Focus Mode button appears. Activating it switches to neighbourhood view: type a hostname and click Focus to load only the 2-hop subgraph around that device using the topology_neighborhood query. Click Exit Focus Mode to return to the full graph.

Topology Overlays

Both Blast Radius and Path Analysis pages offer an Overlay on Topology / Show path on Topology button after results are returned. Clicking it stores the result in memory and navigates to the Topology page, which applies the overlay automatically:

  • Blast Radius overlay — impacted nodes highlighted in rose; non-impacted nodes dimmed; a dismissible banner shows the focal device and endpoint count.
  • Path Analysis overlay — matched firewall nodes highlighted in emerald; a banner shows src → dst. Click Dismiss to clear.

7.3 Device Inventory (/devices)

A virtualized table of all collected network devices, supporting datasets of 10,000+ rows at 60 fps. Data is cached client-side for 5 minutes.

Filters

  • Search — free-text match against hostname, vendor, and model
  • Vendor — multi-select pill filter (Cisco, Juniper, Palo Alto, etc.)
  • Has firewall rules — toggle to show only devices with collected firewall policies

Active filter count is shown on the Filters button; click Clear all inside the panel to reset.

Row Actions

  • Click any row — opens the Inspector Drawer with the 6-tab device detail panel.
  • Show in Topology — navigates to the Topology page and focuses the selected device.
  • Export JSON — downloads the currently filtered device list as a JSON file.

Column Visibility

Click the Columns button (top-right of the table) to show or hide individual columns (Vendor, Model, OS Version, Serial, Collected At).

7.4 Endpoint Search (/endpoints)

Two modes are available via the toggle in the page header:

Search Mode

Locate a single host by IP address or MAC address.

  • IP mode — accepts a single IPv4/IPv6 address or a CIDR prefix; an optional VRF field narrows results to a specific routing domain.
  • MAC mode — accepts any standard MAC format (colon, hyphen, or dotted-quad).

The Command Palette auto-fills and fires a search when you type an IP or MAC and press Enter.

Inventory Mode

Loads all known endpoints (up to 10,000) into a virtualized table with the same column controls as Device Inventory. Click any row to open the Inspector Drawer.

Orphaned Endpoints

An expandable amber panel at the bottom of the page shows endpoints that have no associated subnet record — a sign that the IPAM configuration may be incomplete. Backed by the endpoints_without_location query.

7.5 Subnets & IP Schema (/subnets) analyst+

An IPAM-style view for exploring subnet allocations and tracking address hygiene. Requires analyst persona or higher.

Query Modes

ModeInputQueryResult
By subnetCIDR + optional VRFips_in_subnetAll IP addresses allocated within the prefix, with VRF column
By deviceDevice hostnamesubnets_on_deviceAll subnets configured on that device (network_address, prefix_length, VRF, tenant)

Orphaned IPs

An expandable amber section runs the orphaned_ips query on first open and shows IPs that are configured on interfaces but do not belong to any known subnet definition. This is a common indicator of misconfiguration or missing subnet entries in the graph.

VRF-aware queries
Both By subnet and the orphaned IPs query are VRF-aware. Leave the VRF field blank to see results across all routing domains, or enter a VRF name (e.g. CORP, GUEST) to narrow the scope.

7.6 Firewall Policies (/firewall) security+

Displays a filterable, searchable table of all collected firewall rules across all devices.

Filters

  • Device — filter by firewall hostname
  • Zone pair — source zone / destination zone dropdowns
  • Action — allow / deny / drop / reject
  • Enabled — show only active or disabled rules
  • Search — full-text search across rule name, zones, and address objects

Expanded Row

Click any rule row to expand the detail panel showing: source zones, destination zones, source addresses, destination addresses, services, protocols, ports, logging state, and rule comments. Click the row again to collapse.

Deny Rules Summary

The Deny Rules tab (or the deny_rules_summary query) shows all deny/drop/reject rules across every firewall — useful for quickly auditing what the perimeter explicitly blocks.

7.7 Path Analysis (/path-analysis) security+

Interactive source-to-destination path analysis through the firewall rule chain.

  1. Enter the Source IP address.
  2. Enter the Destination IP address.
  3. Optionally enter Protocol (e.g. tcp) and Destination Port (e.g. 443).
  4. Click Analyse Path.

Results display a PERMITTED (green) or DENIED (red) verdict banner, followed by a per-firewall breakdown of the first-matching rule, its action, rule name, and the zone pair that matched.

After results appear, click Show path on Topology to navigate to the Topology page with the matched firewall devices highlighted in emerald.

Path Analysis Accuracy
Results reflect the firewall rules collected at the last meshq collect run. Always recollect after policy changes before relying on path analysis results for change control decisions.

7.8 Blast Radius (/blast-radius)

Simulate the impact of losing a device, interface, VLAN, or subnet, and see the downstream endpoints that would be affected.

Query Types

ModeParametersQuery
DeviceHostnameblast_radius_device
InterfaceHostname + interface nameblast_radius_interface
VLANVLAN IDblast_radius_vlan
SubnetCIDR prefixblast_radius_subnet

After results are returned, click Overlay on Topology to navigate to the Topology page with impacted nodes highlighted in rose and a dismissible banner showing the focal device and endpoint count.

7.9 Change Center (/history)

Tracks network state over time using an in-memory ring buffer of up to 288 snapshots (24 hours at 5-minute intervals). Three tabs provide different views of change data.

Trend Charts tab

Live sparkline charts showing device count, endpoint count, and firewall rule count over time, updated via SSE.

Network Diff tab

Select two timestamps using the from/to date pickers and click Compare to call GET /history/diff. The response is presented as a three-column diff:

  • Removed — devices or rules present in the earlier snapshot but absent in the later
  • Unchanged — items present in both snapshots
  • Added — items present in the later snapshot but absent in the earlier

What-If Simulation tab Pro+

Submit a proposed topology change and see its impact before making any modifications to the live network.

Two input modes are available:

  • Fields mode — structured inputs for proposed device count and firewall rule count
  • JSON mode — raw NetworkFacts textarea for submitting specific devices, interfaces, and firewall rules

Results show current vs. proposed counts with a delta card and a list of new device hostnames. The simulation banner reads SIMULATION — not live data to prevent confusion. The endpoint is rate-limited to 10 requests per minute; a cooldown timer is shown when the limit is reached.

7.10 Automation (/automation) network+

Export network data and trigger external system synchronisation. Requires the network persona or higher.

Ansible Dynamic Inventory

Download an Ansible-compatible inventory file via the GET /inventory/ansible endpoint.

  • Select format: JSON (for ansible-inventory --list) or INI (legacy format)
  • Click Download inventory.json (or .ini) — the file is fetched and saved to disk
  • Devices are grouped by vendor; devices with collected firewall rules appear in the additional firewalls group

Expand Copy automation snippet to get a pre-filled curl command with your API key for use in CI pipelines or Ansible dynamic inventory scripts.

NetBox Sync Enterprise

The NetBox Sync card is displayed only when NETBOX_URL and NETBOX_TOKEN are configured. It shows the configured sync direction (push / pull / both) and provides a Dry Run Sync button that calls POST /admin/netbox/sync?dry_run=true and displays the proposed changes without committing them.

7.11 Admin (/admin) admin only

The Admin page is restricted to the admin persona. It provides five tabs for managing the running instance.

TabContents
IdentityCurrent API key (masked), authentication mode, and your active persona (access level)
RBACView and edit the current RBAC policy YAML; click Reload Policy to hot-reload without restarting
BackendRuntime config: graph backend, Redis URL, cluster mode, license plan and expiry
SnapshotsRing buffer of recent metric snapshots with timestamps and device/rule fingerprint counts
DiagnosticsCopy Support Bundle — collects masked admin config, last 5 snapshot timestamps, and RBAC source into a JSON blob and copies it to the clipboard for pasting into a support ticket
Settings redirect
The old /settings URL permanently redirects to /admin. Update any bookmarks or automation scripts that reference the old path.
Chapter 8

Query API Reference

The Query API exposes all 25 named queries via a RESTful HTTP interface. Queries are defined in registry.yaml and have dual implementations for Neo4j (Cypher) and PostgreSQL (SQL).

8.1 Authentication

All query endpoints require the X-API-Key HTTP header. Set the API key with the API_KEY environment variable at startup.

curl -H "X-API-Key: your-api-key" http://localhost:8000/queries/

A missing or invalid key returns 401 Unauthorized.

8.2 API Endpoints

MethodPathDescription
GET/queries/List all 25 available queries with metadata
GET/queries/{name}Get details for a single query
POST/queries/{name}/executeExecute a query with parameters
GET/healthShallow health check (process alive)
GET/health/readyDeep readiness check (database connectivity)
GET/history/diffCompare two network snapshots and return a change summary Pro+
POST/graph/whatifSimulate a proposed topology change against the current snapshot Pro+

/history/diff

Compare two network snapshots by timestamp and receive a structured diff of topology and firewall policy changes.

GET /history/diff?from_ts=2026-02-01T00:00:00Z&to_ts=2026-02-24T00:00:00Z
X-API-Key: your-api-key

# Response
{
  "from_ts": "2026-02-01T00:00:00Z",
  "to_ts": "2026-02-24T00:00:00Z",
  "devices_added": ["fw-dmz-02"],
  "devices_removed": [],
  "rules_added": ["fw-dmz-02:permit-80"],
  "rules_removed": ["fw-core-01:deny-8080"],
  "delta": {
    "devices": 1,
    "firewall_rules": 0
  }
}

/graph/whatif

Submit a partial NetworkFacts payload representing a proposed change. The API returns a comparison of the proposed state against the latest snapshot, including counts of new devices and firewall rules. Requires a Pro or Enterprise license and is rate-limited to 10 requests per minute.

POST /graph/whatif
Content-Type: application/json
X-API-Key: your-api-key

{
  "devices": [...],
  "interfaces": [...],
  "firewall_rules": [...]
}

# Response
{
  "proposed": {"devices": 21, "firewall_rules": 62},
  "current":  {"devices": 20, "firewall_rules": 58},
  "delta":    {"devices": 1,  "firewall_rules": 4},
  "new_devices": ["fw-dmz-new"],
  "new_firewall_rules": ["fw-dmz-new:deny-any", ...]
}

Execute Request Body

POST /queries/{name}/execute
Content-Type: application/json
X-API-Key: your-api-key

{
  "parameters": { "device": "sw-core-01" },
  "limit": 1000,
  "offset": 0,
  "output_format": "json"
}
FieldTypeDefaultDescription
parametersobject{}Query parameters (names must match registry definition)
limitinteger1000Maximum rows to return (1–10,000)
offsetinteger0Row offset for pagination
output_formatstringjsonjson or csv

8.3 Query Categories

Topology Queries

Query NameParametersDescription
device_neighborsdevice_name: stringAll devices directly connected to the named device
interface_neighborsdevice_a: string, device_b: stringInterfaces connecting two specific devices
topology_edges(none)All device-to-device edges for full graph visualisation Advanced
topology_neighborhooddevice: string, depth: integer (default 2)N-hop BFS subgraph rooted at the given device — returns all devices and links within the specified hop depth Pro+

Endpoint Queries

Query NameParametersDescription
locate_endpoint_by_ipip: string, vrf: string (optional)Find endpoint record by IPv4 or IPv6 address; results include vrf field
locate_endpoint_by_macmac: stringFind endpoint by MAC address (any common format)
endpoints_on_interfacedevice: string, interface: stringAll endpoints on a specific port

Blast Radius Queries Advanced

Query NameParametersDescription
blast_radius_interfacedevice: string, interface: stringEndpoints impacted if an interface goes down
blast_radius_devicedevice: stringEndpoints impacted if an entire device goes down
blast_radius_vlanvlan: integerAll endpoints in a specific VLAN
blast_radius_subnetcidr: stringEndpoints dependent on a subnet (CIDR notation)

Addressing Queries

Query NameParametersDescription
ips_in_subnetcidr: string, vrf: string (optional)IP addresses allocated within a subnet; results include vrf field
subnets_on_devicedevice: stringAll subnets present on a device
orphaned_ipsvrf: string (optional)IPs with no associated subnet record; results include vrf field

Hygiene Queries

Query NameParametersDescription
devices_without_neighbors(none)Devices with no topology neighbours (isolated)
interfaces_without_ips(none)Interfaces that have no IP address assigned
endpoints_without_location(none)Endpoints that cannot be traced to a physical port

Inventory & Summary Queries

Query NameParametersDescription
summary_stats(none)Dashboard counts: devices, interfaces, endpoints, VLANs
all_devices(none)All devices with vendor, model, OS version, serial

Firewall Queries

Query NameParametersGate
all_firewall_devices(none)
firewall_rules_by_devicedevice: string
deny_rules_summary(none)
firewall_rules_by_zone_pairsource_zone: string, destination_zone: stringAdvanced
path_analysissource_ip, destination_ip, protocol?, destination_port?Advanced

8.4 Pagination & Export

Pagination

# Page 1 (rows 0–99)
{"parameters": {}, "limit": 100, "offset": 0}

# Page 2 (rows 100–199)
{"parameters": {}, "limit": 100, "offset": 100}

# Response includes total count
{
  "total": 1843,
  "offset": 100,
  "limit": 100,
  "rows": [...]
}

CSV Export

curl -H "X-API-Key: $API_KEY" \
  http://localhost:8000/queries/all_devices/execute \
  -d '{"parameters": {}, "output_format": "csv"}' \
  -o devices.csv

The response is a streaming CSV with a Content-Disposition: attachment; filename="all_devices.csv" header.

Chapter 9

MCP Server

The MeshOptixIQ MCP (Model Context Protocol) server enables AI assistants — Claude Desktop, Claude Code, and any MCP-compatible client — to query the network graph directly using natural language, without requiring manual REST API calls.

License Requirement
The MCP server requires a Pro or Enterprise license. It will not start on a Starter plan.

9.1 Overview & Requirements

The MCP server connects directly to Neo4j or PostgreSQL using the same query files as the REST API. It runs as a stdio transport process — the AI client starts it as a subprocess and communicates over stdin/stdout. No HTTP server or port is required.

Install the MCP Extras

pip install "meshoptixiq-network-discovery[mcp]"

# Or with PostgreSQL support
pip install "meshoptixiq-network-discovery[postgres,mcp]"

Environment Variables (MCP)

VariableRequiredDescription
MESHOPTIXIQ_LICENSE_KEYRequiredPro or Enterprise license key
GRAPH_BACKENDOptionalneo4j (default) or postgres
NEO4J_URIIf Neo4jBolt connection URI
NEO4J_PASSWORDRequiredNeo4j password
MCP_MAX_RESULT_ROWSOptionalRow cap per tool call (default 1000)

Test the MCP Server

GRAPH_BACKEND=neo4j \
NEO4J_URI=bolt://localhost:7687 \
NEO4J_PASSWORD=your-password \
MESHOPTIXIQ_LICENSE_KEY=mq-prod-xxxxxxxxxx \
  meshq-mcp

The server will print its initialisation options to stderr and then wait for MCP protocol messages on stdin. Use Ctrl+C to stop.

9.2 Claude Desktop Setup

Add MeshOptixIQ to your Claude Desktop configuration file:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json

Python Installation

{
  "mcpServers": {
    "meshoptixiq": {
      "command": "meshq-mcp",
      "env": {
        "GRAPH_BACKEND": "neo4j",
        "NEO4J_URI": "bolt://localhost:7687",
        "NEO4J_USER": "neo4j",
        "NEO4J_PASSWORD": "your-password",
        "MESHOPTIXIQ_LICENSE_KEY": "mq-prod-xxxxxxxxxx"
      }
    }
  }
}

Docker

{
  "mcpServers": {
    "meshoptixiq": {
      "command": "docker",
      "args": [
        "run", "--rm", "-i",
        "--network", "host",
        "-e", "GRAPH_BACKEND=neo4j",
        "-e", "NEO4J_URI=bolt://localhost:7687",
        "-e", "NEO4J_PASSWORD=your-password",
        "-e", "MESHOPTIXIQ_LICENSE_KEY=mq-prod-xxxxxxxxxx",
        "meshoptixiq/discovery-agent:latest",
        "meshq-mcp"
      ]
    }
  }
}

Restart Claude Desktop after editing the config. MeshOptixIQ should appear in the tool panel (plug icon).

9.3 Claude Code Setup

Add MeshOptixIQ as an MCP server in your Claude Code project:

# In your project directory
claude mcp add meshoptixiq meshq-mcp \
  --env GRAPH_BACKEND=neo4j \
  --env NEO4J_URI=bolt://localhost:7687 \
  --env NEO4J_PASSWORD=your-password \
  --env MESHOPTIXIQ_LICENSE_KEY=mq-prod-xxxxxxxxxx

Or add it globally (available in all projects):

claude mcp add --global meshoptixiq meshq-mcp \
  --env MESHOPTIXIQ_LICENSE_KEY=mq-prod-xxxxxxxxxx \
  --env NEO4J_PASSWORD=your-password

9.4 Available Tools, Resources & Prompts

Tools (23 total)

Tool NameKey ParametersGate
meshq_inventory_summary_stats(none)api_access
meshq_inventory_all_deviceslimit?api_access
meshq_topology_device_neighborsdevice_nameapi_access
meshq_topology_interface_neighborsdevice_a, device_bapi_access
meshq_topology_topology_edgeslimit?advanced_queries
meshq_endpoints_locate_by_ipipapi_access
meshq_endpoints_locate_by_macmacapi_access
meshq_endpoints_endpoints_on_interfacedevice, interfaceapi_access
meshq_blast_radius_interfacedevice, interfaceadvanced_queries
meshq_blast_radius_devicedeviceadvanced_queries
meshq_blast_radius_vlanvlanadvanced_queries
meshq_blast_radius_subnetcidradvanced_queries
meshq_addressing_ips_in_subnetcidrapi_access
meshq_addressing_subnets_on_devicedeviceapi_access
meshq_addressing_orphaned_ips(none)api_access
meshq_hygiene_devices_without_neighbors(none)api_access
meshq_hygiene_interfaces_without_ips(none)api_access
meshq_hygiene_endpoints_without_location(none)api_access
meshq_firewall_all_firewall_devices(none)api_access
meshq_firewall_rules_by_devicedeviceapi_access
meshq_firewall_deny_rules_summary(none)api_access
meshq_firewall_rules_by_zone_pairsource_zone, destination_zoneadvanced_queries
meshq_firewall_path_analysissource_ip, destination_ip, protocol?, destination_port?advanced_queries

Resources (6 total)

Resources expose read-only network data as background context for AI reasoning.

URIDescription
network://inventory/summaryDevice/interface/endpoint/VLAN counts
network://inventory/devicesFull device inventory (capped at 500)
network://topology/edgesAll device-to-device connections
network://health/hygieneMerged hygiene report (3 queries)
network://schema/queriesAll 25 query definitions from registry.yaml (no DB call)
network://firewall/policiesAll firewall devices + deny-rule summary

Prompts (6 pre-defined templates)

Prompt NameArgumentsPurpose
network_incident_triageaffected_device, incident_description?Blast radius + neighbours for active incident
network_change_impact_assessmentdevice, interface?, change_description?Pre-maintenance impact report
network_endpoint_huntidentifier, identifier_typeLocate endpoint by IP or MAC, trace to port
network_addressing_auditcidr?IP addressing gaps and orphaned IPs
network_hygiene_report(none)Full hygiene check with remediation checklist
network_firewall_auditdevice?Audit security policies: any/any permits, zone pairs, deny hits

Example Conversations

User: "What would be the impact if sw-core-01 went offline right now?"

Claude: [calls meshq_blast_radius_device with device="sw-core-01"]
        [calls meshq_topology_device_neighbors with device_name="sw-core-01"]
        "If sw-core-01 went offline, 847 endpoints would lose connectivity,
         distributed across VLANs 10, 20, and 100. Three distribution
         switches — sw-dist-01, sw-dist-02, and sw-dist-03 — would lose
         their uplink. I recommend scheduling maintenance in a 2-hour window
         outside business hours..."
Chapter 10

Advanced Deployment

10.1 Production Docker Compose

The following Docker Compose configuration runs MeshOptixIQ, Neo4j, and an Nginx reverse proxy with automatic restarts and persistent volumes.

version: '3.8'

services:
  neo4j:
    image: neo4j:5-community
    restart: unless-stopped
    volumes:
      - neo4j-data:/data
      - neo4j-logs:/logs
    environment:
      NEO4J_AUTH: neo4j/${NEO4J_PASSWORD}
      NEO4J_PLUGINS: '["apoc"]'
      NEO4J_dbms_memory_heap_initial__size: 1G
      NEO4J_dbms_memory_heap_max__size: 4G
    healthcheck:
      test: ["CMD", "neo4j", "status"]
      interval: 30s
      timeout: 10s
      retries: 5

  meshoptixiq:
    image: meshoptixiq/discovery-agent:latest
    restart: unless-stopped
    depends_on:
      neo4j:
        condition: service_healthy
    ports:
      - "127.0.0.1:8000:8000"
    environment:
      GRAPH_BACKEND: neo4j
      NEO4J_URI: bolt://neo4j:7687
      NEO4J_USER: neo4j
      NEO4J_PASSWORD: ${NEO4J_PASSWORD}
      MESHOPTIXIQ_LICENSE_KEY: ${MESHOPTIXIQ_LICENSE_KEY}
      API_KEY: ${API_KEY}
      CORS_ORIGINS: https://meshoptixiq.yourdomain.com
    volumes:
      - meshoptixiq-cache:/app/cache
      - ./inventory.yaml:/app/configs/inventory.yaml:ro
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
      interval: 30s
      timeout: 5s
      retries: 3

  nginx:
    image: nginx:alpine
    restart: unless-stopped
    depends_on:
      - meshoptixiq
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
      - ./nginx/certs:/etc/nginx/certs:ro

volumes:
  neo4j-data:
  neo4j-logs:
  meshoptixiq-cache:

Store secrets in a .env file (never committed to version control):

NEO4J_PASSWORD=strong-random-password-here
MESHOPTIXIQ_LICENSE_KEY=mq-prod-xxxxxxxxxx
API_KEY=strong-random-api-key-here
# Start the stack
docker compose --env-file .env up -d

# View logs
docker compose logs -f meshoptixiq

# Run collection inside the container
docker compose exec meshoptixiq meshq collect \
  --source /app/configs/inventory.yaml

10.2 PostgreSQL Backend

Switch to PostgreSQL by setting GRAPH_BACKEND=postgres and providing a POSTGRES_DSN. The PostgreSQL schema is created automatically on first ingest.

services:
  postgres:
    image: postgres:16
    restart: unless-stopped
    environment:
      POSTGRES_DB: meshoptixiq
      POSTGRES_USER: meshoptixiq
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    volumes:
      - postgres-data:/var/lib/postgresql/data

  meshoptixiq:
    image: meshoptixiq/discovery-agent:latest
    environment:
      GRAPH_BACKEND: postgres
      POSTGRES_DSN: postgresql://meshoptixiq:${POSTGRES_PASSWORD}@postgres:5432/meshoptixiq
      MESHOPTIXIQ_LICENSE_KEY: ${MESHOPTIXIQ_LICENSE_KEY}
      API_KEY: ${API_KEY}

10.3 Reverse Proxy & TLS

Always front the MeshOptixIQ API with a reverse proxy that terminates TLS in production. A minimal Nginx config:

server {
    listen 443 ssl;
    server_name meshoptixiq.yourdomain.com;

    ssl_certificate     /etc/nginx/certs/fullchain.pem;
    ssl_certificate_key /etc/nginx/certs/privkey.pem;
    ssl_protocols       TLSv1.2 TLSv1.3;
    ssl_ciphers         HIGH:!aNULL:!MD5;

    # Security headers
    add_header Strict-Transport-Security "max-age=31536000" always;
    add_header X-Frame-Options DENY;
    add_header X-Content-Type-Options nosniff;

    location / {
        proxy_pass         http://127.0.0.1:8000;
        proxy_set_header   Host $host;
        proxy_set_header   X-Real-IP $remote_addr;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Proto $scheme;
        proxy_read_timeout 60s;
    }
}

# Redirect HTTP → HTTPS
server {
    listen 80;
    server_name meshoptixiq.yourdomain.com;
    return 301 https://$host$request_uri;
}
Let's Encrypt
Use Certbot with the Nginx plugin to obtain and auto-renew free TLS certificates: certbot --nginx -d meshoptixiq.yourdomain.com
Chapter 11

Troubleshooting

11.1 Installation & Startup Issues

API reports 503 on /health/ready

Cause: The graph backend (Neo4j or PostgreSQL) is not reachable.

  1. Verify the database process is running: docker compose ps neo4j
  2. Test the Bolt connection from the MeshOptixIQ host: nc -zv <neo4j-host> 7687
  3. Check the NEO4J_URI variable — use bolt:// not http:// for the Bolt protocol
  4. Verify the Neo4j credentials: NEO4J_USER / NEO4J_PASSWORD
  5. Check Neo4j logs: docker compose logs neo4j

Web UI shows a blank page / 404

Cause: The UI_DIR path does not contain the built React app.

  • In Docker: UI_DIR defaults to /app/static — verify the container was built correctly.
  • In bare-metal: Set UI_DIR to the directory containing the Vite build output (dist/).

meshq command not found

  • Ensure the package is installed: pip show meshoptixiq-network-discovery
  • Verify the Python bin directory is in $PATH: which meshq || python3 -m network_discovery.cli version

11.2 License Issues

License not found

No license key found. Please set MESHOPTIXIQ_LICENSE_KEY
or create ~/.meshoptixiq/license.key

Set the environment variable or create the license file as described in §3.3.

License expired

LicenseExpiredError: License has expired.

Renew at meshoptixiq.com/pricing or via the customer portal at portal.meshoptixiq.com.

Device limit exceeded

LicenseDeviceMismatchError: Device limit exceeded for this license

Your Pro license allows up to 5 registered installation hosts. To transfer a registration or add seats, contact hello@meshoptixiq.com.

Grace period active

Running in grace period. 48.3 hours remaining.

The licensing server was not reachable during the last 24-hour check. Ensure api.meshoptixiq.com:443 (HTTPS) is accessible from the host. The application will continue working for 72 hours from the last successful validation.

Feature not available

FeatureNotAvailableError: Feature 'advanced_queries' is not available
on the 'starter' plan. Upgrade to 'pro' or higher.

Upgrade your plan at meshoptixiq.com/pricing.

11.3 Collection Failures

SSH connection refused / timeout

Collection failed for sw-core-01: SSH connection timed out
  1. Verify the device is reachable: ping <device-ip>
  2. Test SSH directly: ssh -v <username>@<device-ip> -p 22
  3. Check that TCP/22 is allowed through any intermediate firewalls between the MeshOptixIQ host and the device
  4. Increase the timeout in the inventory file: timeout: 60

Authentication failure

Authentication failed for sw-core-01: Invalid credentials
  • Verify the username and password in the inventory file or environment variables
  • Confirm the account has SSH access and the necessary show-command privileges
  • For devices requiring enable mode, add secret: "{{ env.ENABLE_SECRET }}" to the device definition

Parser produced zero results

If meshq parse reports 0 interfaces or 0 endpoints for a device:

  • Check the raw cache: cat ~/.meshoptixiq/cache/<hostname>/*.txt
  • Ensure the device_type in the inventory file matches the actual device OS
  • Confirm the device returns expected output for commands like show interfaces and show ip arp

11.4 Query & API Errors

400 Bad Request — Missing parameters

{"detail": "Missing parameters: ['device_name']"}

Include all required parameters in the parameters object. Check the query schema with GET /queries/{name}.

401 Unauthorized

The X-API-Key header is missing or the value does not match the API_KEY environment variable.

404 Not Found — Query not found

The query name in the URL is misspelled. Use GET /queries/ to list all valid query names.

500 Internal Server Error on query execution

  • Check FastAPI logs: docker compose logs meshoptixiq
  • Verify the graph backend is reachable: GET /health/ready
  • Ensure data has been ingested: run the full collection pipeline and then retry

MCP server exits immediately

ERROR: MCP server requires a pro or enterprise license.

Set MESHOPTIXIQ_LICENSE_KEY to a valid Pro or Enterprise key. Starter keys will not start the MCP server.

Chapter 12

Security Best Practices

12.1 Secret Management

Never Commit Secrets
License keys, API keys, database passwords, and SSH credentials must never be committed to version control. Use .gitignore to exclude .env files and inventory files containing credentials.

Recommended Secret Storage

EnvironmentRecommended Tool
Docker / Docker ComposeDocker Secrets, .env file (restricted permissions)
KubernetesKubernetes Secrets, Sealed Secrets, or Vault Agent Injector
VM / Bare-metalHashiCorp Vault, AWS Secrets Manager, or ~/.meshoptixiq/license.key with chmod 600
CI/CDGitHub Actions secrets, GitLab CI variables, or Vault

12.2 Network Security

  • Always run behind a reverse proxy with TLS. The FastAPI process itself does not terminate TLS. Use Nginx, Caddy, or a load balancer in front of port 8000.
  • Restrict CORS. Set CORS_ORIGINS to your specific UI origin rather than leaving it as *.
  • Bind to loopback. In Docker Compose, publish as 127.0.0.1:8000:8000 so only the reverse proxy can reach the FastAPI process.
  • Firewall the database. Neo4j's Bolt port (7687) and PostgreSQL (5432) should only be accessible from the MeshOptixIQ host — never exposed to the public internet.
  • Segment the collector. The host running meshq collect needs SSH access to network devices. Place it on a dedicated management VLAN with strict ACLs.

12.3 SSH Credential Security

  • Create a dedicated read-only service account on each network device for MeshOptixIQ. Grant only the minimum commands required (show interfaces, show arp, show mac address-table, show ip route).
  • Prefer SSH key authentication over passwords. Store private keys at ~/.ssh/meshoptixiq_ed25519 with chmod 600.
  • Rotate SSH credentials periodically and update the inventory file accordingly.
  • Disable password authentication on devices if SSH keys are in use.

12.4 API Key Hardening

  • Generate a strong random API key: openssl rand -hex 32 (64 hex characters)
  • Rotate the API key periodically. Rolling restarts with the new key ensure zero-downtime rotation.
  • Log all API requests. The FastAPI middleware logs method, path, status code, and latency for each request.
  • Consider adding a WAF (Web Application Firewall) in front of the API for production deployments.

12.5 Keeping Current

  • Subscribe to security advisories at github.com/meshoptixiq/meshoptixiq/security/advisories.
  • Update the Docker image regularly: docker pull meshoptixiq/discovery-agent:latest.
  • Monitor the PYTHONPATH dependencies for CVEs using pip audit in development environments.
  • Neo4j and PostgreSQL should run the latest patch release of their major version.
Chapter 13

Enterprise Features Enterprise

The enterprise container image extends the standard runtime with four additional capability layers: secrets management (pull credentials from an external vault at startup), SSO/OIDC authentication, structured audit logging to SIEM platforms, and APM observability. All features are gated behind the enterprise Python extras and are activated by environment variables; the standard image is completely unaffected.

13.1 Enterprise Container Image

Enterprise images are published alongside the standard image with an enterprise- version prefix:

# Pull latest enterprise image
docker pull meshoptixiq/discovery-agent:enterprise-latest

# Or pin to a specific release
docker pull meshoptixiq/discovery-agent:enterprise-1.3.0

Startup Sequence

The enterprise container runs a Python entrypoint (/app/entrypoint.py) before starting the API server. The entrypoint:

  1. Reads SECRETS_PROVIDER to determine which secrets backend to use.
  2. Fetches secrets from the configured backend and merges them into the process environment.
  3. Replaces itself with uvicorn via os.execvpe — uvicorn runs as PID 1 with all secrets injected as environment variables. No secrets are stored on disk.

Minimal Quickstart

docker run -d \
  -e NEO4J_URI=bolt://neo4j:7687 \
  -e NEO4J_PASSWORD=your-password \
  -e MESHOPTIXIQ_LICENSE_KEY=mq-ent-xxxxxxxxxx \
  -e API_KEY=your-api-key \
  -p 8000:8000 \
  meshoptixiq/discovery-agent:enterprise-latest
Standard Image Compatibility
All standard deployment patterns work unchanged with the enterprise image. Enterprise features are opt-in via environment variables. If no enterprise-specific variables are set, the container behaves identically to the standard image.

13.2 Secrets Management

Set SECRETS_PROVIDER to pull credentials from an external secrets store at startup. The fetched values are merged into the container environment before uvicorn starts, so all application config (database passwords, API keys, license keys) can be stored securely in your vault.

Secrets in all backends must be stored as a JSON object mapping environment variable names to values:

{"API_KEY": "...", "NEO4J_PASSWORD": "...", "MESHOPTIXIQ_LICENSE_KEY": "..."}
ProviderSECRETS_PROVIDERDescription
None (default)noneNo secrets fetching; rely on environment variables set directly.
HashiCorp VaultvaultFetch from a KV v2 path. Supports token, AppRole, and Kubernetes auth.
AWS Secrets ManagerawsFetch by secret name. Uses the ambient IAM role or explicit credentials.
Azure Key VaultazureFetch named secrets from an Azure Key Vault. Supports managed identity.
GCP Secret ManagergcpFetch secret versions from GCP. Supports Workload Identity.

HashiCorp Vault

SECRETS_PROVIDER=vault
VAULT_ADDR=https://vault.corp.local:8200
VAULT_SECRET_PATH=secret/data/meshoptixiq   # KV v2 path
Auth MethodRequired Variables
tokenVAULT_AUTH_METHOD=token, VAULT_TOKEN
approleVAULT_AUTH_METHOD=approle, VAULT_ROLE_ID, VAULT_SECRET_ID
kubernetesVAULT_AUTH_METHOD=kubernetes, VAULT_K8S_ROLE (reads service account token automatically)

AWS Secrets Manager

SECRETS_PROVIDER=aws
AWS_SECRET_NAME=prod/meshoptixiq    # Secret name
AWS_REGION=us-east-1                # Defaults to us-east-1

Authentication uses the standard AWS credential chain: IAM instance profile, ECS task role, AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY, or ~/.aws/credentials.

Azure Key Vault

SECRETS_PROVIDER=azure
AZURE_KEY_VAULT_URL=https://myvault.vault.azure.net
AZURE_SECRET_NAMES=meshoptixiq-secrets          # Comma-separated list of secret names

Authentication uses DefaultAzureCredential (managed identity, environment, or CLI). If a secret value is valid JSON it is unpacked into multiple env vars; otherwise the whole value is stored under the uppercased, hyphen-to-underscore secret name.

GCP Secret Manager

SECRETS_PROVIDER=gcp
GCP_PROJECT_ID=my-project
GCP_SECRET_IDS=meshoptixiq-secrets:latest   # Comma-separated name:version pairs

Omit the version suffix to default to latest. Authentication uses Application Default Credentials (Workload Identity, GOOGLE_APPLICATION_CREDENTIALS, or gcloud auth).

13.3 Enterprise Authentication (OIDC)

By default MeshOptixIQ uses a single shared X-API-Key header. The enterprise image adds OIDC/JWT Bearer token authentication via the AUTH_MODE environment variable.

AUTH_MODEBehaviour
api_key (default)Standard X-API-Key header only. OIDC is not active.
oidcBearer JWT required; X-API-Key is rejected.
bothAccepts a valid Bearer JWT or a valid X-API-Key. Recommended for mixed client environments.

OIDC Configuration

# Required when AUTH_MODE=oidc or AUTH_MODE=both
AUTH_MODE=both
OIDC_DISCOVERY_URL=https://company.okta.com/.well-known/openid-configuration
OIDC_CLIENT_ID=meshoptixiq-api-client

# Optional: comma-separated list of scopes every token must contain
OIDC_REQUIRED_SCOPES=read:queries

On startup the API fetches the OIDC discovery document to locate the JWKS endpoint, then caches the JSON Web Key Set (JWKS) for one hour. Key rotation is handled automatically: if a token's kid is not in the cache, the JWKS is immediately refreshed before re-validating.

Token Validation

Every Bearer token is validated for:

  • Signature — verified against the JWKS public keys.
  • Expiry (exp) — expired tokens receive 401 Unauthorized.
  • Issuer (iss) — must match the OIDC discovery URL base.
  • Audience (aud) — must match OIDC_CLIENT_ID.
  • Required scopes — if OIDC_REQUIRED_SCOPES is set, all listed scopes must be present; missing scopes return 403 Forbidden.

On successful validation, a UserContext object (containing sub, email, roles, groups, scopes) is attached to request.state.user and made available to audit logging.

Startup Validation
If AUTH_MODE=oidc or AUTH_MODE=both is set, the API will fail to start if OIDC_DISCOVERY_URL and OIDC_CLIENT_ID are not also set. This prevents silent misconfigurations.

13.4 Audit Logging & SIEM

Set AUDIT_LOG_ENABLED=true to emit a structured audit event after every request to /queries/* endpoints. Events are shipped simultaneously to all configured targets.

Audit Event Schema

{
  "event":       "query_executed",
  "timestamp":   "2026-02-22T10:30:00Z",
  "request_id":  "uuid-v4",
  "client_ip":   "10.0.0.1",
  "user":        "alice@corp.com",       // JWT sub or "api_key_client"
  "method":      "POST",
  "path":        "/queries/topology_summary/execute",
  "query_name":  "topology_summary",
  "status":      200,
  "row_count":   42,
  "elapsed_ms":  85.3
}

Shipping Targets

TargetActivationKey Variables
Structured stdoutAlways active when AUDIT_LOG_ENABLED=true
Splunk HECSPLUNK_HEC_URL + SPLUNK_HEC_TOKENSPLUNK_INDEX (default: meshoptixiq), SPLUNK_SOURCETYPE
ElasticsearchELASTICSEARCH_URLELASTICSEARCH_API_KEY, ELASTICSEARCH_INDEX (default: meshoptixiq-audit)
OpenSearchOPENSEARCH_URLOPENSEARCH_USERNAME, OPENSEARCH_PASSWORD, OPENSEARCH_INDEX
WebhookAUDIT_WEBHOOK_URLAUDIT_WEBHOOK_TOKEN (sent as Bearer header)
Failure Isolation
Each shipping target operates independently. A failure writing to Elasticsearch does not prevent delivery to Splunk or the webhook — all targets are attempted simultaneously and failures are logged as warnings without disrupting API responses.

Splunk Example

AUDIT_LOG_ENABLED=true
SPLUNK_HEC_URL=https://splunk.corp.local:8088/services/collector/event
SPLUNK_HEC_TOKEN=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
SPLUNK_INDEX=network-audit

Elasticsearch Example

AUDIT_LOG_ENABLED=true
ELASTICSEARCH_URL=https://elastic.corp.local:9200
ELASTICSEARCH_API_KEY=base64-encoded-api-key
ELASTICSEARCH_INDEX=meshoptixiq-audit

13.5 Observability

The enterprise image activates APM tracing by detecting known exporter environment variables. Backends are tried in priority order; only the first match is activated.

PriorityBackendActivation VariableMechanism
1Datadog (native)DD_AGENT_HOSTddtrace.patch_all() + FastAPI instrumentation
2New Relic (native)NEW_RELIC_LICENSE_KEYnewrelic.agent.initialize()
3OTLPOTEL_EXPORTER_OTLP_ENDPOINTOpenTelemetry SDK + BatchSpanProcessor + FastAPI auto-instrumentation
None(no variable set)No-op; standard operation

Datadog

DD_AGENT_HOST=datadog-agent    # Hostname of the Datadog agent
DD_SERVICE=meshoptixiq          # Service name in Datadog APM (default: meshoptixiq)
DD_ENV=production               # Environment tag
DD_VERSION=1.3.0                # Version tag

New Relic

NEW_RELIC_LICENSE_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
NEW_RELIC_APP_NAME=MeshOptixIQ (default: meshoptixiq)

OpenTelemetry (OTLP)

The OTLP exporter is compatible with any OTel Collector, including Datadog in OTLP mode, New Relic OTLP ingest, Grafana Tempo, Jaeger, and Splunk Observability.

OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4317
OTEL_SERVICE_NAME=meshoptixiq
OTEL_TRACES_EXPORTER=otlp    # Set to "none" to disable span export while keeping the SDK

Appendix A: Environment Variables Reference

All environment variables recognised by MeshOptixIQ are documented here. Variables are grouped by subsystem. Required variables are marked with Required; all others are optional.

A.1 Database

VariableDefaultDescription
GRAPH_BACKENDneo4jGraph backend to use: neo4j or postgres.
NEO4J_URIbolt://localhost:7687Neo4j Bolt URI. Required when GRAPH_BACKEND=neo4j.
NEO4J_USERneo4jNeo4j username.
NEO4J_PASSWORDRequired Neo4j password. Do not embed in images; use secrets.
POSTGRES_DSNpostgresql://postgres:postgres@localhost:5432/network_discoveryFull PostgreSQL connection string. Required when GRAPH_BACKEND=postgres.

A.2 API Server

VariableDefaultDescription
API_KEYrequiredShared secret for X-API-Key header authentication. Server will not start without this set.
CORS_ORIGINSComma-separated list of allowed CORS origins. Defaults to empty (cross-origin denied). Use specific origins in production (https://app.example.com).
UI_DIRFilesystem path to compiled React SPA (/app/static in Docker). When set, FastAPI serves the SPA at /.

A.3 Licensing

VariableDefaultDescription
MESHOPTIXIQ_LICENSE_KEYRequired License key string. Alternatively, place the key in ~/.meshoptixiq/license.key.
MESHOPTIXIQ_LICENSE_API_URLhttps://api.meshoptixiq.com/license/validateLicense validation endpoint URL. Override for testing with the mock server.

A.4 Device Collection

VariableDefaultDescription
DEVICE_PASSWORDDefault SSH password applied to all devices that do not specify an explicit password in the inventory file. Prefer SSH key auth.
COLLECTION_WORKERS10Maximum number of concurrent SSH collection threads.
COLLECTION_TIMEOUT60Per-device SSH connection timeout in seconds.
COLLECTION_COMMAND_TIMEOUT120Per-command execution timeout in seconds. Increase for slow devices.

A.5 MCP Server

VariableDefaultDescription
MCP_MAX_RESULT_ROWS1000Maximum rows returned per MCP tool call. Prevents oversized AI context windows.

A.6 Enterprise Features Enterprise

Variables below are only evaluated by the enterprise container image. See Chapter 13 for full context.

Secrets Management

VariableDefaultDescription
SECRETS_PROVIDERnoneSecrets backend: none | vault | aws | azure | gcp.
VAULT_ADDRHashiCorp Vault server URL (e.g. https://vault:8200).
VAULT_AUTH_METHODtokenVault auth method: token | approle | kubernetes.
VAULT_TOKENVault token (token auth only).
VAULT_ROLE_IDAppRole role ID.
VAULT_SECRET_IDAppRole secret ID.
VAULT_K8S_ROLEKubernetes auth role name.
VAULT_SECRET_PATHsecret/data/meshoptixiqKV v2 path to the secrets object.
AWS_SECRET_NAMEAWS Secrets Manager secret name.
AWS_REGIONus-east-1AWS region for Secrets Manager.
AZURE_KEY_VAULT_URLAzure Key Vault endpoint URL.
AZURE_SECRET_NAMESComma-separated Azure secret names to fetch.
GCP_PROJECT_IDGCP project ID for Secret Manager.
GCP_SECRET_IDSComma-separated name:version pairs (version defaults to latest).

Authentication

VariableDefaultDescription
AUTH_MODEapi_keyAuth strategy: api_key | oidc | both.
OIDC_DISCOVERY_URLRequired when AUTH_MODE=oidc or both. OIDC provider discovery endpoint.
OIDC_CLIENT_IDRequired when AUTH_MODE=oidc or both. Expected audience claim.
OIDC_REQUIRED_SCOPESComma-separated list of scopes every token must contain.

Audit Logging

VariableDefaultDescription
AUDIT_LOG_ENABLEDfalseSet to true to activate audit event emission.
SPLUNK_HEC_URLSplunk HTTP Event Collector endpoint.
SPLUNK_HEC_TOKENSplunk HEC authentication token.
SPLUNK_INDEXmeshoptixiqTarget Splunk index.
SPLUNK_SOURCETYPEmeshoptixiq:apiSplunk sourcetype.
ELASTICSEARCH_URLElasticsearch endpoint URL.
ELASTICSEARCH_API_KEYElasticsearch API key (base64-encoded id:key).
ELASTICSEARCH_INDEXmeshoptixiq-auditTarget Elasticsearch index.
OPENSEARCH_URLOpenSearch endpoint URL.
OPENSEARCH_USERNAMEOpenSearch basic auth username.
OPENSEARCH_PASSWORDOpenSearch basic auth password.
OPENSEARCH_INDEXmeshoptixiq-auditTarget OpenSearch index.
AUDIT_WEBHOOK_URLGeneric SIEM webhook URL (POST JSON).
AUDIT_WEBHOOK_TOKENBearer token sent in the webhook Authorization header.

Observability

VariableDefaultDescription
DD_AGENT_HOSTDatadog agent hostname; activates ddtrace native mode.
DD_SERVICEmeshoptixiqDatadog service name.
DD_ENVDatadog environment tag (e.g. production).
DD_VERSIONDatadog version tag.
NEW_RELIC_LICENSE_KEYNew Relic ingest key; activates native APM agent.
NEW_RELIC_APP_NAMEmeshoptixiqApp name in New Relic UI.
OTEL_EXPORTER_OTLP_ENDPOINTOTLP endpoint; activates OpenTelemetry SDK (e.g. http://otel-collector:4317).
OTEL_SERVICE_NAMEmeshoptixiqOTel service name.
OTEL_TRACES_EXPORTERotlpSet to none to disable span export while keeping the SDK active.

Appendix B: CLI Command Reference

The meshq command-line interface is the primary tool for operating MeshOptixIQ on the command line. All subcommands are documented below.

B.1 meshq ingest

Collect device data and ingest it into the graph database in a single step.

meshq ingest [OPTIONS]

Options:
  --source PATH        Inventory YAML file path.  [required]
  --backend TEXT       Override GRAPH_BACKEND: neo4j or postgres.
  --workers INT        Number of parallel SSH workers (default: 10).
  --dry-run            Parse inventory and validate connectivity without writing to DB.
  -v, --verbose        Enable verbose SSH output.
  --help               Show this message and exit.

Examples:
  meshq ingest --source configs/inventory.yaml
  meshq ingest --source inventory.yaml --backend postgres --workers 20
  meshq ingest --source inventory.yaml --dry-run

B.2 meshq collect

Collect raw CLI output from devices and save to disk (without ingesting into the database).

meshq collect [OPTIONS]

Options:
  --source PATH        Inventory YAML file path.  [required]
  --output DIR         Directory to write collected output files (default: ./collected/).
  --workers INT        Number of parallel SSH workers (default: 10).
  -v, --verbose        Enable verbose SSH output.
  --help               Show this message and exit.

Examples:
  meshq collect --source inventory.yaml --output /data/raw/
  meshq collect --source inventory.yaml -v

B.3 meshq parse

Parse previously collected raw output files and ingest into the database.

meshq parse [OPTIONS]

Options:
  --input DIR          Directory of collected output files.  [required]
  --backend TEXT       Override GRAPH_BACKEND: neo4j or postgres.
  --help               Show this message and exit.

Examples:
  meshq parse --input /data/raw/
  meshq parse --input ./collected/ --backend postgres

B.4 meshq status

Display license status, graph backend connectivity, and database statistics.

meshq status [OPTIONS]

Options:
  --json               Output status as JSON.
  --help               Show this message and exit.

Output includes:
  - License plan, expiry date, and device ID
  - Graph backend type and connection status
  - Device count, interface count, endpoint count
  - Firewall rule count (if any collected)

Examples:
  meshq status
  meshq status --json | jq .license

B.5 meshq version

Print the installed MeshOptixIQ version and exit.

meshq version

Example output:
  MeshOptixIQ 1.2.0 (Python 3.12.3, Neo4j backend)

B.6 meshq-mcp

Start the MCP server on stdio transport. Intended to be launched by an MCP client (Claude Desktop, Claude Code), not invoked directly.

meshq-mcp

Environment variables required:
  GRAPH_BACKEND, NEO4J_URI, NEO4J_PASSWORD (or POSTGRES_DSN)
  MESHOPTIXIQ_LICENSE_KEY (pro or enterprise plan required)

The process reads JSON-RPC 2.0 messages on stdin and writes responses to stdout.
All log output goes to stderr.

Example (test with mcp dev):
  mcp dev network_discovery/network_discovery/mcp/server.py

Appendix C: Supported Vendor Matrix

The tables below list every vendor OS supported by MeshOptixIQ, the parser identifier used in inventory files, and the specific data types collected.

C.1 Network Device Parsers

VendorOS / PlatformParser IDInterfacesARPMAC TableRoutingLLDP/CDP
CiscoIOS / IOS-XEcisco_ios✅ CDP
CiscoNX-OScisco_nxos✅ CDP
CiscoASAcisco_asa
JuniperJunOSjuniper_junos✅ LLDP
AristaEOSarista_eos✅ LLDP
ArubaAOS-CXaruba_os✅ LLDP
Palo AltoPAN-OSpaloalto_panos
FortinetFortiOSfortinet

C.2 Firewall Policy Parsers

VendorOS / PlatformParser IDSecurity PoliciesAddress ObjectsService Objects
Palo AltoPAN-OSpaloalto_panos
JuniperJunOS SRXjuniper_junos✅ (address books)
FortinetFortiOSfortinet✅ (incl. groups)
CiscoASA OScisco_asa✅ (ACLs)✅ (object groups)

C.3 Netmiko Device Type Mapping

The device_type field in inventory YAML maps directly to Netmiko device types. The parser ID and Netmiko device type are usually the same string.

Parser IDNetmiko device_type
cisco_ioscisco_ios
cisco_nxoscisco_nxos
cisco_asacisco_asa
juniper_junosjuniper_junos
arista_eosarista_eos
aruba_osaruba_aoscx
paloalto_panospaloalto_panos
fortinetfortinet

Appendix D: Query Registry

The query registry (network_discovery/queries/registry.yaml) defines all 25 named queries. Each query has a Neo4j Cypher variant (.cypher) and a PostgreSQL variant (.sql). Parameters shown use the notation $parameter. Queries marked Pro+ require a Pro or Enterprise license.

D.1 Topology

Query NameParametersDescription
device_neighbors$device_nameReturns all devices directly connected to the given device, with connecting interface and link metadata.
interface_neighbors$interface_idReturns the neighbour interface and device for a single interface, derived from LLDP/CDP adjacency.
topology_edgesReturns all physical adjacency edges in the graph as source device, source interface, destination interface, destination device tuples. Used for topology visualisation.
topology_neighborhood$device, $depth (integer, default 2)N-hop BFS subgraph rooted at the given device. Returns all devices and connecting links within the specified hop depth. Supports up to 4 hops. Pro+

D.2 Endpoints

Query NameParametersDescription
locate_by_ip$ip, $vrf (optional)Locates the switch port and device where the given IP address was last seen in the ARP table. Results include a vrf column.
locate_by_mac$macLocates the switch port and device where the given MAC address was last seen. MAC addresses are normalised to lowercase colon-separated form.
endpoints_on_interface$interface_idReturns all endpoints (IP + MAC pairs) seen on a specific interface.

D.3 Addressing

Query NameParametersDescription
ips_in_subnet$subnet (CIDR), $vrf (optional)Returns all IP addresses and associated devices/interfaces within the given subnet. Pass $vrf to filter to a specific routing instance. Results include a vrf column.
subnets_on_device$device_nameReturns all IP prefixes (subnets) assigned to interfaces on the given device.
orphaned_ips$vrf (optional)Returns IP addresses present in the ARP table that do not match any interface subnet — possible rogue hosts or configuration errors. Pass $vrf to scope to one routing instance. Results include a vrf column.

D.4 Hygiene

Query NameParametersDescription
devices_without_neighborsReturns devices with no LLDP/CDP neighbours — isolated or misconfigured devices.
interfaces_without_ipsReturns non-loopback, non-management interfaces that have no IP address assigned.
endpoints_without_locationReturns endpoints (IP/MAC) seen in the ARP table but not associated with any switch port via the MAC table.

D.5 Blast Radius

Query NameParametersDescription
blast_radius_interface$interface_idReturns all endpoints reachable from a given interface, up to 3 hops. Useful for planned interface maintenance.
blast_radius_device$device_nameReturns all endpoints and devices reachable from a given device via adjacency graph traversal.
blast_radius_vlan$vlan (integer)Returns all interfaces and endpoints participating in the given VLAN ID.
blast_radius_subnet$subnet (CIDR)Returns all devices and interfaces whose configured subnets overlap with the given prefix.

D.6 Inventory / Summary

Query NameParametersDescription
summary_statsReturns aggregate counts: total devices, interfaces, endpoints, subnets, firewall rules, and last-updated timestamp.
all_devicesReturns every device node with hostname, vendor, platform, management IP, and device type.

D.7 Firewall

Query NameParametersDescription
all_firewall_devicesReturns all devices that have at least one collected firewall rule, with rule counts.
firewall_rules_by_device$device_nameReturns all firewall rules for the given device, ordered by rule sequence number.
firewall_rules_by_zone_pair$source_zone, $destination_zoneReturns rules across all firewalls that match the given source and destination zone pair.
path_analysis$source_ip, $destination_ip, $protocol?, $destination_port?Returns the first-matching firewall rule per device for traffic between the two IPs. Protocol and port are optional filter arguments.
deny_rules_summaryReturns all deny/drop/reject rules across every firewall, with device and rule metadata.

Appendix E: License Plan Comparison

MeshOptixIQ is available in four plans. The Community plan is free and requires no license key. Paid plans (Starter, Pro, Enterprise) include a license key enforced at runtime by the licensing gates module. All paid plans include the core collection pipeline, full topology ingestion, and the CLI toolchain.

Feature Community Starter Pro Enterprise
Devices1Up to 100Up to 750Unlimited
Graph BackendNeo4jNeo4jNeo4j / PostgreSQLNeo4j / PostgreSQL
REST API
Topology QueriesBasicFullFullFull
Blast Radius Analysis
Firewall Policy Analysis
What-If Simulation
MCP Server (AI Integration)
Redis Clustering
RBAC
OIDC / SSO
NetBox Sync
SOAR Webhooks
Audit Logging
SupportCommunityEmailPriority EmailSLA + Dedicated
Grace period
All paid plans include a 72-hour offline grace period. If the licensing server is unreachable, the application continues to function for 72 hours before blocking CLI operations. The Community plan has no license server dependency.

To upgrade your plan or purchase a license, visit meshoptixiq.com/pricing. For enterprise volume licensing or air-gapped deployments, contact sales@meshoptixiq.com.

Appendix F: MCP Tool Reference

The MeshOptixIQ MCP server exposes 23 tools across 8 categories. All tools return JSON-serialised results as TextContent. Tools marked advanced_queries require a Pro or Enterprise license; all others require api_access (Pro or Enterprise).

F.1 Inventory

Tool NameParametersGateReturns
meshq_inventory_summary_statsapi_accessCounts of devices, interfaces, endpoints, subnets, firewall rules.
meshq_inventory_all_devicesapi_accessFull device list with hostname, vendor, platform, management IP.

F.2 Topology

Tool NameParametersGateReturns
meshq_topology_device_neighborsdevice: stringapi_accessDevices directly adjacent to the given device, with link metadata.
meshq_topology_interface_neighborsinterface_id: stringapi_accessNeighbour interface and device for a single interface.
meshq_topology_topology_edgesadvanced_queriesAll adjacency edges: source device, source interface, dest interface, dest device.

F.3 Endpoints

Tool NameParametersGateReturns
meshq_endpoints_locate_by_ipip: stringapi_accessSwitch port and device where the IP was last seen in the ARP table.
meshq_endpoints_locate_by_macmac: stringapi_accessSwitch port and device where the MAC was last seen. MAC is normalised automatically.
meshq_endpoints_endpoints_on_interfaceinterface_id: stringapi_accessAll IP/MAC endpoint pairs seen on the interface.

F.4 Addressing

Tool NameParametersGateReturns
meshq_addressing_ips_in_subnetsubnet: string (CIDR)api_accessIPs and associated devices/interfaces within the subnet.
meshq_addressing_subnets_on_devicedevice: stringapi_accessAll IP prefixes assigned to interfaces on the device.
meshq_addressing_orphaned_ipsapi_accessIPs in ARP table that don't match any interface subnet.

F.5 Hygiene

Tool NameParametersGateReturns
meshq_hygiene_devices_without_neighborsapi_accessDevices with no LLDP/CDP neighbours.
meshq_hygiene_interfaces_without_ipsapi_accessNon-loopback, non-management interfaces with no IP address.
meshq_hygiene_endpoints_without_locationapi_accessEndpoints present in ARP but not located via MAC table.

F.6 Blast Radius

Tool NameParametersGateReturns
meshq_blast_radius_interfaceinterface_id: stringadvanced_queriesAll endpoints reachable from the interface (up to 3 hops).
meshq_blast_radius_devicedevice: stringadvanced_queriesAll endpoints and devices reachable from the device.
meshq_blast_radius_vlanvlan: integeradvanced_queriesAll interfaces and endpoints in the VLAN.
meshq_blast_radius_subnetsubnet: string (CIDR)advanced_queriesAll devices and interfaces overlapping with the subnet.

F.7 Firewall

Tool NameParametersGateReturns
meshq_firewall_all_firewall_devicesapi_accessAll devices with collected firewall rules, with rule counts.
meshq_firewall_rules_by_devicedevice: stringapi_accessAll rules for the device, ordered by sequence number.
meshq_firewall_deny_rules_summaryapi_accessAll deny/drop/reject rules across every firewall.
meshq_firewall_rules_by_zone_pairsource_zone: string, destination_zone: stringadvanced_queriesRules matching the zone pair across all firewalls.
meshq_firewall_path_analysissource_ip: string, destination_ip: string, protocol?: string, destination_port?: stringadvanced_queriesFirst-matching rule per firewall for the traffic flow. Empty result = implicit deny.

F.8 MCP Resources

Resources are read-only data URIs exposed by the MCP server. Clients can subscribe to resources for automatic updates.

URIGateContents
network://inventory/summaryapi_accessSummary stats object (same as summary_stats query).
network://inventory/devicesapi_accessFull device list (up to 500 rows).
network://topology/edgesapi_accessAll adjacency edges for visualisation.
network://health/hygieneapi_accessMerged hygiene report: isolated devices, interfaces without IPs, unlocated endpoints.
network://schema/queriesnoneFull query registry YAML contents — no DB call, no gate.
network://firewall/policiesapi_accessAll firewall devices and deny rules summary in a single object.

F.9 MCP Prompts

Prompts are reusable, parameterised instruction templates that AI assistants can invoke to start structured analysis workflows.

Prompt NameArgumentsPurpose
network_incident_triageaffected_device, incident_description?Guides the assistant through blast radius assessment and neighbour analysis for incident response.
network_change_impact_assessmentdevice, interface?, change_description?Pre-maintenance impact analysis: affected endpoints, downstream devices, risk summary.
network_endpoint_huntidentifier, identifier_type (ip|mac)Locate an endpoint by IP or MAC and trace its physical switch port location.
network_addressing_auditcidr?Identify IP gaps, orphaned IPs, and subnets nearing exhaustion.
network_hygiene_reportFull hygiene assessment with prioritised remediation recommendations.
network_firewall_auditdevice?Security policy audit: any/any permit rules, zone pairs lacking explicit deny, top deny-hit rules.

Index

Entries reference chapter sections (e.g., 3.2) or appendix sections (e.g., A.3). Page numbers appear in printed output.

A

B

  • Backup & restore — 10.4
  • Blast radius — 8.1, D.5, F.6
  • Build (Docker) — 3.2

C

D

E

F

G

H

I

  • Index (query) — 4.2
  • Installation — 3
  • Inventory file — 5.1

J

K

  • Kubernetes — 10.5

L

M

N

O

P

Q

R

  • REST API — 8
  • Resources (MCP) — 9.4, F.8

S

  • Secrets management — 12.1
  • Security best practices — 12
  • SSH — 5.1, 12.3
  • Starter plan — 3.3, Appendix E
  • System requirements — 2

T

  • TLS — 10.2
  • Topology UI — 7.2
  • Troubleshooting — 11

U–Z