Skip to main content
Glama
MukeshA39
by MukeshA39
README.md
# Redfish Fleet MCP

Conversational, lights-out monitoring for a fleet of bare-metal servers.

This is a small [Model Context Protocol (MCP)](https://modelcontextprotocol.io)
server that sits in front of your servers' baseboard management controllers
(BMCs) and exposes a set of clearly named, purpose-built tools to an AI
assistant. Instead of logging into dozens of management consoles one at a time,
you ask questions in plain language:

> Are there any errors on the Buckeye servers?
>
> Is any server in the fleet running outdated firmware?
>
> Check PSU redundancy across the fleet and report only the degraded units.

The server speaks **Redfish** (the DMTF standard) on one side, so it works with
any compliant BMC — Dell iDRAC, HPE iLO, and others — and the Model Context
Protocol on the other.

> This repository is a generalized, vendor-neutral companion to a trade article.
> The included `servers.yml` is entirely synthetic: fictional hostnames and
> IP addresses from the RFC 5737 documentation ranges. Replace it with your own
> fleet before pointing it at real hardware.

## Why

Every server includes a BMC that monitors temperatures, fans, power supplies,
disks, and firmware independently of the host OS. The telemetry is excellent;
the problem is the *cost of reading it*. Checking a fleet by hand — one slow
web console at a time — is expensive enough that it rarely happens, so faults
accumulate silently. A classic example is a power supply that fails in a
redundant pair: the server keeps running, the BMC may still report the unit as
"present and healthy," and nobody notices the lost redundancy until the second
supply dies.

This project closes that ergonomics gap. It does not add a new capability; it
makes an existing one cheap enough to use routinely.

## Architecture

![Architecture diagram](docs/architecture.svg)

The system is a thin **translation layer** in front of the fleet. It has three
tiers:

1. **The operator** asks a question in plain language.
2. **The AI assistant** (any MCP-capable client) interprets the question and
   selects one of the server's tools.
3. **The MCP server** — this project — receives the tool call and translates it
   into one or more standard Redfish REST requests, fans them out across the
   fleet, and returns a concise summary.

On the south side, the MCP server talks to each server's baseboard management
controller (BMC) over **Redfish** — the DMTF industry standard — using HTTP
Basic Auth over HTTPS. Because it speaks plain Redfish, it is **vendor-neutral**:
the same code works against Dell iDRAC, HPE iLO, and any other Redfish-compliant
controller.

### How the Redfish integration is actually done

This is worth being explicit about, since it is a common point of confusion:

- The integration is a **direct, hand-written async HTTP client**
  (`redfish_client.py`) built on [`httpx`](https://www.python-httpx.org/). Each
  method performs a `GET`/`POST` against a documented Redfish resource path
  (for example `/redfish/v1/Systems/System.Embedded.1`) and parses the JSON.
- It does **not** use Ansible. There is no Dell OpenManage / `dellemc.openmanage`
  collection, no `community.general` Redfish modules (`redfish_info`,
  `idrac_redfish_command`, etc.), and no vendor SDK anywhere in this project.
  The only runtime dependencies are `httpx`, `pyyaml`, `fastmcp`, and `flask`
  (dashboard only).
- Authentication is HTTP Basic Auth over HTTPS, the common denominator across
  BMC vendors. Self-signed BMC certificates are tolerated (`verify=False`),
  which is typical for out-of-band management networks.

An Ansible-based approach (e.g. `dellemc.openmanage.idrac_redfish_*`) is a valid
alternative architecture, but it is a different design with different tradeoffs
(playbook orchestration, inventory plugins, vendor-specific modules). This
project deliberately keeps the data path as a small, dependency-light client so
the same code is portable across vendors and easy to read.

### Files

| File | Role |
|------|------|
| `server.py` | Defines the MCP tools the assistant can call |
| `redfish_client.py` | Async Redfish client — the actual HTTPS calls to each BMC |
| `config.py` | Loads inventory, handles credentials (in-memory + hash check) |
| `servers.yml` | Fleet inventory (synthetic example included) |
| `start.sh` | Launcher that prompts for the BMC password |
| `dashboard.py` | Optional Flask dashboard: polls the fleet and serves a US map |
| `templates/`, `static/` | Dashboard front-end (HTML, CSS, data-driven JS map) |
| `docs/` | Companion article and architecture diagram |

## Optional dashboard

In addition to the conversational interface, an optional web dashboard renders
the fleet on a US map (sites plotted from their `lat`/`lon`, colored by health)
with per-site cards and a drill-down detail modal. The map is **fully
data-driven** from `servers.yml` — there is no hardcoded topology — so it works
for any fleet.

```bash
BMC_PASSWORD=... python dashboard.py
# then open http://localhost:5050
```

It binds to `127.0.0.1` by default. The dashboard and the MCP server share the
same `config.py` and `redfish_client.py`, so they always agree on the fleet.

The front-end assets are **vendored locally** in `static/` (d3 v7, topojson-client
v3, and the us-atlas states TopoJSON), so the dashboard runs fully offline with
no external CDN calls — appropriate for isolated out-of-band management networks.
Those bundled files retain their original licenses (d3 and topojson: ISC;
us-atlas: ISC / US Census Bureau public-domain source).

## Tools

| Tool | Description | Access |
|------|-------------|--------|
| `list_servers` | List all managed servers | Read-only |
| `get_system_health` | System health for one server | Read-only |
| `get_all_health` | Fleet-wide health summary | Read-only |
| `get_temperatures` | Thermal sensor readings | Read-only |
| `get_fan_status` | Fan speed and health | Read-only |
| `get_power_usage` | Power consumption and PSU status | Read-only |
| `get_storage_status` | RAID and disk health | Read-only |
| `get_system_event_log` | Hardware event log entries | Read-only |
| `get_lifecycle_log` | Lifecycle / managed-system log | Read-only |
| `get_firmware_inventory` | Firmware versions for one server | Read-only |
| `get_all_firmware` | Key firmware across the fleet | Read-only |
| `check_firmware_drift` | Flag servers off the per-model baseline | Read-only |
| `get_network_interfaces` | NIC info (MAC, IP, speed) | Read-only |
| `check_errors` | Combined error check for one server | Read-only |
| `check_all_errors` | Quick error scan across the fleet | Read-only |
| `check_psu_fleet` | Fleet-wide PSU redundancy scan | Read-only |
| `reboot_server` | Graceful or forced restart | **Requires confirmation** |

## Design notes

- **Credentials never touch disk.** The password is entered once at startup,
  held in memory for the session, and discarded on exit. Only a salted
  SHA-256 hash is stored locally, purely to validate correct entry.
- **One mutating tool.** Only `reboot_server` changes state, and it requires
  explicit confirmation. Asking a question should never cost more than getting
  an answer.
- **Unreachable is reported, not hidden.** Fleet scans explicitly mark servers
  whose BMC cannot be reached rather than silently omitting them. A monitor
  that quietly drops nodes misrepresents fleet state.
- **PSU logic is SEL-confirmed.** A raw "0W + OK" reading is ambiguous. The
  PSU check only reports a problem when the System Event Log confirms a failure
  or lost redundancy, which keeps the signal trustworthy.

## Setup

### 1. Install dependencies

```bash
cd redfish-fleet-mcp
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
```

### 2. Configure your fleet

Replace the synthetic entries in `servers.yml` with your own servers:

```yaml
default_username: root

servers:
  - name: edge1-buckeye
    fqdn: edge1-buckeye.example.net
    bmc_ip: "192.0.2.11"
    region: east
    site: buckeye
    model: Example PowerServer A1
```

### 3. Register with your MCP client

See `mcp_config_example.json`. Point it at the absolute path of `start.sh`:

```json
{
  "mcpServers": {
    "redfish-fleet": {
      "command": "bash",
      "args": ["/absolute/path/to/redfish-fleet-mcp/start.sh"],
      "disabled": false
    }
  }
}
```

### 4. Launch

`start.sh` prompts for the BMC password, then runs the server over stdio.
Alternatively, set `BMC_PASSWORD` (and optionally `BMC_USERNAME`) in the
environment.

## Requirements

- Python 3.9+
- Network access to your BMC IPs over HTTPS (port 443)
- Any Redfish-compliant BMC (tested conceptually against Dell iDRAC 9)

## Limitations

- No predictive/ML failure analysis — this is deliberate.
- No autonomous remediation — the single reboot tool is confirmation-gated.
- Fleet scans poll sequentially, so a full sweep is not instantaneous. Prefer
  targeted per-site queries for routine checks.
- If a BMC is unreachable, the tool reports it as such — useful information, but
  not a substitute for direct access when a controller itself has failed.

## License

MIT — see [LICENSE](LICENSE).