Content
# giorria
**giorria** (Irish: *hare*) is a fully reproducible network automation lab that pairs an all-Arista cEOS topology with an AI-powered operations platform built on the [Model Context Protocol (MCP)](https://modelcontextprotocol.io/).
The lab demonstrates how to build natural-language network operations tooling on top of open-source infrastructure -- offline config analysis, live telemetry, structured audit trails, and AAA accounting -- wired together so that a language model can answer questions like *"which BGP sessions are not established?"* or *"show me the config diff since the last meaningful change"* using real network data.
---
## What's inside
| Component | Technology | Purpose |
|---|---|---|
| Network lab | Containerlab + Arista cEOS 4.35.1F | 6-node spine-leaf fabric, two ASes, inter-fabric peering |
| Offline analysis | [Batfish](https://www.batfish.org/) + pybatfish | Config validation, BGP topology, reachability, route tables |
| Fact store | PostgreSQL | Normalised network state populated by the ingest pipeline |
| Config backup | [Oxidized](https://github.com/ytti/oxidized) | Polls all devices, triggers Batfish pipeline on change |
| Object store | MinIO | Snapshot archives (ZIP) |
| Telemetry | gNMIc + Prometheus | OpenConfig interface counters, system state |
| Logging | Grafana Loki | Structured pipeline audit trail, TACACS+ accounting |
| Dashboards | Grafana | Pre-provisioned datasources (Prometheus + Loki) |
| AAA | TACACS+ | Authentication and command accounting for all 6 devices |
| MCP server | FastMCP (Python) | LLM-accessible tools for all of the above |
---
## Topology
```
Fabric A (AS 65100 / 65101 / 65102) Fabric B (AS 65200 / 65201 / 65202)
arista-spine1 172.100.100.2 arista-spine2 172.100.100.3
Eth1 10.1.1.0/31 Eth1 10.2.0.0/31
Eth2 10.1.2.0/31 Eth2 10.2.0.2/31
Eth3 10.99.0.0/31 --- inter-fabric --------- Eth3 10.99.0.1/31
| |
+---------+ +---------+---------+
| | | |
arista- arista- arista-leaf3 arista-leaf4
leaf1 leaf2 (AS 65201) (AS 65202)
(65101) (65102)
```
Management network: `172.100.100.0/24` (created by Containerlab as `clab-mgmt`)
---
## Quick start
### 1. Prerequisites
- Docker + Docker Compose
- [Containerlab](https://containerlab.dev/install/)
- Arista cEOS 4.35.1F image (see [lab/README.md](lab/README.md) for how to obtain it)
### 2. Import the cEOS image
```bash
docker import cEOS-lab-4.35.1F.tar.xz ceos:4.35.1F
```
### 3. Configure environment variables
```bash
python3 configure.py
```
The script asks for a lab password and a TACACS+ shared key (or generates
both for you), then writes all `.env` files and patches device startup
configs, Oxidized credentials, and gNMIc credentials with the chosen
password.
> **Important:** Run this *before* deploying the lab — it patches the
> device startup configs that Containerlab bind-mounts into each container.
### 4. Deploy the network lab
```bash
cd lab/
sudo containerlab deploy -t topology.yml --reconfigure
cd ..
```
> The `--reconfigure` flag forces cEOS containers to re-apply their startup
> configuration from the bind-mounted `.cfg` files. Without it, containers
> reuse whatever is persisted in flash from a previous deploy and
> configuration changes are silently ignored.
This creates the `clab-mgmt` Docker network that all services attach to.
### 5. Start the stack
```bash
docker compose \
--profile core \
--profile observability \
--profile oxidized \
--profile tacacs \
up -d
```
### 6. Run the MCP server
```bash
cd network-mcp/
# Install with uv (recommended)
uv sync
uv run network-mcp
# Or with pip
pip install -e .
network-mcp
```
The server listens on `http://localhost:8080/mcp` (Streamable HTTP transport).
Point Claude Desktop or any MCP-compatible client at that URL.
---
## Service ports
| Service | Port | Notes |
|---|---|---|
| MCP server | 8080 | Streamable HTTP -- `http://localhost:8080/mcp` |
| pgAdmin | 8006 | PostgreSQL browser |
| MinIO console | 8005 | Object store UI |
| MinIO S3 API | 8004 | |
| Oxidized | 8888 | Web UI + REST API |
| Grafana | 3000 | Dashboards |
| Prometheus | 9090 | Metrics |
| Loki | 3100 | Log aggregation |
| Batfish | 9996 | Config analysis API |
| PostgreSQL | 5432 | Fact store |
| TACACS+ | 49/tcp | AAA |
---
## Compose profiles
| Profile | Services |
|---|---|
| `core` | Batfish, PostgreSQL, pgAdmin, MinIO, ingest pipeline |
| `observability` | Loki, Prometheus, gNMIc, Grafana |
| `oxidized` | Oxidized config backup daemon |
| `tacacs` | TACACS+ server + Promtail log shipper |
---
## How the pipeline works
```
Arista device config changes
|
v
Oxidized polls & stores in git
| post_store hook
v
export-to-batfish.sh
writes .cfg to shared volume
| HTTP POST
v
ingest (FastAPI)
+-- archives configs
+-- runs Batfish analysis
+-- writes facts to PostgreSQL
+-- uploads snapshot ZIP to MinIO
| structured events
v
Loki (audit trail)
```
The MCP server queries PostgreSQL first (no device contact), escalating to live eAPI calls only when real-time state is needed.
---
## MCP tool categories
| Prefix | Source | Use when |
|---|---|---|
| `netlab_*` | PostgreSQL fact store | Inventory, interfaces, BGP, routes -- use first |
| `arista_*` | Live eAPI | Real-time counters, running config, arbitrary show commands |
| `batfish_*` | Batfish | Reachability, config validation, offline topology analysis |
| `loki_*` | Loki | Pipeline audit trail, failure analysis, per-node history |
| `prometheus_*` | Prometheus | gNMI interface counters, system telemetry |
| `tacacs_*` | Loki (TACACS stream) | AAA audit -- who logged in, what commands ran |
---
## Repository layout
```
giorria/
+-- compose.yml # All services, profile-gated
+-- configure.py # One-shot setup: generates .env files, patches configs
+-- .env.example # Root environment template
+-- lab/ # Containerlab topology + device configs
+-- ingest/ # FastAPI pipeline orchestrator + Dockerfile
+-- oxidized/ # Oxidized config.example, router.db, hook scripts
+-- collector/ # Prometheus, Loki, gNMIc, Grafana configs
| +-- gnmic.example.yml # gNMIc template (configure.py generates gnmic.yml)
+-- tacacs/ # TACACS+ server (Python RFC 8907 implementation)
+-- network-mcp/ # MCP server (FastMCP, Python, pyproject.toml)
+-- src/network_mcp/
+-- server.py # Tool definitions
+-- config.py # Environment-driven configuration
+-- arista_tools.py # Live eAPI queries
+-- batfish_tools.py # Offline config analysis
+-- postgres_tools.py# Fact store queries
+-- loki_tools.py # Audit trail queries
+-- prometheus_tools.py # gNMI telemetry
+-- tacacs_tools.py # AAA audit queries
```
---
## Documentation
| Guide | Description |
|---|---|
| [Agent Instructions](docs/agent-instructions.md) | Recommended system prompt for MCP clients — tool priority and troubleshooting workflow |
| [Grafana Query Reference](docs/grafana-queries.md) | Example Loki and Prometheus queries for Grafana Explore |
---
## Licence
MIT -- see [LICENSE](LICENSE).