baremetal-mcp
An MCP server for managing bare-metal infrastructure — Redfish BMC operations and Junos switch queries.
Open source Open in the app JSON README (API)
About
An MCP server for managing bare-metal infrastructure — Redfish BMC operations and Junos switch queries.
Details
- Kind
- Plugins
- Topic
- Cloud & DevOps
- Publisher
- sshnaidm
- Origin
- gemini
- Category
- ferramentas
- Version
- 1.0.0
- Stars
- 2
- Forks
- 1
- Last push
- 2026-09-02T19:44:05Z
- Repository state
- ativo
- Language
- Python
- License
- Apache-2.0
- Added
- 2026-08-30 14:13:39
- Updated
- 2026-08-30 14:13:39
- Origin id
sshnaidm/baremetal-mcp
README
# Baremetal MCP Server
An MCP (Model Context Protocol) server for managing bare-metal infrastructure. It exposes Redfish BMC operations (Dell iDRAC, HPE iLO, Supermicro), BMC console capture and command paging, and Junos/Dell OS10 switch queries as tools for AI assistants.
Built with [FastMCP](https://github.com/jlowin/fastmcp), it works with any MCP-compatible client including **Claude Code**, **Gemini CLI**, and others.
## Table of Contents
- [Features](#features)
- [Portable Agent Skills](#portable-agent-skills)
- [Requirements](#requirements)
- [Prerequisites](#prerequisites)
- [Installation](#installation)
- [Claude Code](#claude-code)
- [Gemini CLI](#gemini-cli)
- [Cursor](#cursor)
- [Other MCP Clients](#other-mcp-clients)
- [Configuration](#configuration)
- [Usage](#usage)
## Features
- **Inventory:** Detailed hardware overview (CPUs, Memory, NICs, Storage).
- **Power Control:** On, Off, Graceful Shutdown, and Reboots.
- **Boot Management:** Set one-time boot targets (PXE, CD/ISO, HDD, USB).
- **Virtual Media:** Mount and eject ISO images remotely.
- **Dell-Specific:** Firmware updates and detailed XML inventory exports.
- **BMC Console Tools:** Run guarded Dell SOL/HPE VSP commands in batches, or capture and page through a visually confirmed VNC console.
- **Network Inventory:** Collect Linux network facts, query firmware-visible Redfish NIC ports, save per-host YAML, validate identity and duplicates, and export searchable MAC/IP indexes.
- **Junos Switches:** Query Juniper switch configuration, interfaces, MAC tables, and run arbitrary CLI commands via SSH.
- **Dell OS10 Switches:** Run read-only `show` queries or dry-run/confirm unrestricted CLI sequences across switches via SSH.
- **Parallelism:** Perform actions on multiple servers simultaneously.
- **Caching:** Slow inventory calls (`get_firmware_inventory`, `get_hardware_overview`, `get_system_info`) are cached in memory with TTLs to avoid redundant BMC requests.
## Portable Agent Skills
Model-neutral workflows are available under [`skills/`](skills/) using the standard [Agent Skills](https://agentskills.io/specification) `SKILL.md` format. They use YAML frontmatter plus Markdown instructions and do not require model-specific metadata. See [`SKILLS.md`](SKILLS.md) for the catalog.
## Requirements
Ensure you have Python installed and install the necessary dependencies:
```bash
pip install -e .
```
## Prerequisites
Before using the MCP server with any AI agent, you **must** configure two mandatory environment variables pointing to your server and credentials files:
```bash
# Required — must be set before running Claude Code or Gemini CLI
export REDFISH_CONFIG="/path/to/redfish_servers.yaml"
export REDFISH_SECRETS="/path/to/redfish_secrets.yaml"
```
```bash
# Optional — only if you need firmware ISOs or custom settings
export ISOS_FILE="/path/to/isos.yaml"
export GLOBAL_CONFIG="/path/to/global_config.yaml"
export NETWORK_INVENTORY_DIR="/path/to/network_inventory"
export HARDWARE_INVENTORY_DIR="/path/to/hardware_inventory"
```
Add these to your `~/.bashrc` or `~/.zshrc` to make them permanent. See [Configuration](#configuration) for file format details.
## Installation
### Running manually
```bash
# stdio transport (for MCP clients)
fastmcp run -t stdio main.py
# HTTP transport (for network access)
fastmcp run --port 5004 --host 127.0.0.1 -t streamable-http main.py
```
## Claude Code
### Install as a plugin from GitHub (recommended)
Make sure the [prerequisite env vars](#prerequisites) are exported in your shell, then:
```bash
claude plugin marketplace add sshnaidm/baremetal-mcp
claude plugin install baremetal-mcp@baremetal-mcp-marketplace
```
Verify it works:
```bash
claude mcp list # see configured servers
```
Or within a Claude Code session, run `/mcp` to see active tools and server status.
### Alternative: clone and auto-detect
Clone the repository and open it with Claude Code. The included `.mcp.json` is detected automatically — you'll be prompted to approve the server on first use.
```bash
git clone https://github.com/sshnaidm/baremetal-mcp.git
cd baremetal-mcp
claude
```
### Alternative: manual setup with env vars
Register the server directly and pass config paths as env vars:
```bash
claude mcp add --transport stdio baremetal-mcp \
--env REDFISH_CONFIG=/path/to/redfish_servers.yaml \
--env REDFISH_SECRETS=/path/to/redfish_secrets.yaml \
-- fastmcp run -t stdio /path/to/baremetal-mcp/main.py
```
## Gemini CLI
Make sure the [prerequisite env vars](#prerequisites) are exported in your shell, then install directly from the repository:
```bash
gemini extensions install https://github.com/sshnaidm/baremetal-mcp.git
```
Verify it works:
- `/extensions list` - See installed extensions.
- `/mcp` - See active tools and server status.
## Cursor
Add the server to your Cursor MCP configuration file (`.cursor/mcp.json` in your project or `~/.cursor/mcp.json` globally):
```json
{
"mcpServers": {
"baremetal-mcp": {
"command": "fastmcp",
"args": ["run", "-t", "stdio", "/path/to/baremetal-mcp/main.py"],
"env": {
"REDFISH_CONFIG": "/path/to/redfish_servers.yaml",
"REDFISH_SECRETS": "/path/to/redfish_secrets.yaml"
}
}
}
}
```
## Other MCP Clients
Any MCP-compatible client can use this server via stdio transport. Add it to your client's MCP configuration:
```json
{
"mcpServers": {
"baremetal-mcp": {
"command": "fastmcp",
"args": ["run", "-t", "stdio", "/path/to/baremetal-mcp/main.py"],
"env": {
"REDFISH_CONFIG": "/path/to/redfish_servers.yaml",
"REDFISH_SECRETS": "/path/to/redfish_secrets.yaml"
}
}
}
}
```
Optionally add `GLOBAL_CONFIG` and `ISOS_FILE` env vars if you need custom settings or firmware ISOs.
For HTTP transport instead of stdio:
```json
{
"mcpServers": {
"baremetal-mcp": {
"url": "http://127.0.0.1:5004/mcp"
}
}
}
```
Start the server separately with: `fastmcp run --port 5004 --host 127.0.0.1 -t streamable-http main.py`
## Configuration
The server uses up to four YAML configuration files controlled by environment variables.
| Env var | Default filename | Required | Description |
| --------- | ----------------- | ---------- | ------------- |
| `REDFISH_CONFIG` | `redfish_servers.yaml` | **Yes** | Server/switch definitions (BMC IPs, vendor, tags) |
| `REDFISH_SECRETS` | `redfish_secrets.yaml` | **Yes** | Per-server credentials (username/password) |
| `ISOS_FILE` | `isos.yaml` | No | Firmware/ISO URL catalog |
| `GLOBAL_CONFIG` | `global_config.yaml` | No | Settings overrides (timeouts, retries, cache TTLs) |
| `NETWORK_INVENTORY_DIR` | `network_inventory` | No | Per-host YAML network snapshots; overrides the global setting |
| `HARDWARE_INVENTORY_DIR` | `data/hardware_inventory` | No | Validated Dell XML files and manifests; overrides the global setting |
### Servers Configuration (`redfish_servers.yaml`)
Each entry requires `bmc_ip` (the BMC management address). Connection ports are never inferred by the MCP server: define shared values in `server_defaults` and `switch_defaults`, then override them per target when necessary. `vendor` remains optional and is auto-detected through the configured Redfish endpoint.
```yaml
server_defaults:
redfish:
port: 443
serial_console:
transport: auto
port: 22
verify_ssl: false
switch_defaults:
port: 22
servers:
srv-dell-01:
bmc_ip: "10.10.1.5" # required
vendor: "dell" # optional, auto-detected if omitted
lab: "lab-a"
tags: ["compute", "gpu"]
serial_number: "ABC123" # optional identity guard
expected_host_macs:
- "aa:bb:cc:dd:ee:01"
credential_profile: "dell-lab"
vnc: # optional; all connection values explicit
port: 5901
timeout: 30
key_delay: 0.01
srv-hpe-02:
bmc_ip: "10.10.1.6"
vendor: "hpe"
lab: "lab-b"
```
### Switches Configuration
Switches are defined under a separate `switches:` section in the same file. Each needs a `hostname` and an SSH `port`, either directly or through `switch_defaults`.
```yaml
switches:
lab1-switch:
hostname: "192.168.1.200"
vendor: "Juniper" # optional
model: "Juniper QFX5120" # optional
tags: ["switch", "lab1"] # optional
lab1-dell-switch:
hostname: "192.168.1.201"
vendor: "Dell"
model: "S5232F-ON"
tags: ["switch", "lab1"]
```
### Secrets Configuration (`redfish_secrets.yaml`)
Define the credentials for each server ID.
```yaml
profiles:
dell-lab:
username: "example-dell-user"
password: "example-dell-password"
vnc_password: "example-vnc-password"
srv-dell-01:
# Per-host values override a referenced profile.
password: "example-override-password"
srv-hpe-02:
username: "example-hpe-user"
password: "example-hpe-password"
```
See `*.example.yaml` files for complete format examples.
`boot_from_iso` validates HTTP(S) image URLs, bounds fleet concurrency, verifies that the exact image is inserted, and confirms `Cd`/`Once` before it sends a reset. If verification fails, it does not reboot. A powered-off verified host is started with `On` instead of an invalid restart request. Results retain each accepted, rejected, or ambiguous media/boot mutation, so a late failure cannot make a partially changed host look safe to retry; an accepted reset request is never described as a verified power transition.
`export_hardware_inventory_xml` replaces external Dell export wrappers. It handles case-insensitive `Location` headers, polls task monitors with deadlines and `Retry-After`, rejects cross-BMC redirects or malformed/oversized/non-inventory XML, and requires the XML service tag to match the live Redfish identity before using either a fresh download or cache. It writes XML atomically and creates a checksum manifest. It returns metadata by default; use `include_xml=true` only when the raw payload is needed. For large exports, use `start_hardware_inventory_export` and `get_operation`.
Use `redfish_call` and `parallel_redfish_call` only when no high-level tool covers a standard Redfish resource. They accept same-BMC origin-relative paths only. GET/HEAD/OPTIONS run normally; POST/PUT/PATCH/DELETE make no request by default and require `dry_run=false` plus `confirm_method_path` exactly matching the returned `required_confirmation`. Mutating requests are never automatically replayed after an ambiguous failure, and missing credentials fail closed instead of falling back to vendor defaults.
### BMC Console Commands
`run_console_command_batch` is the normal text interface. It attaches with Dell iDRAC SSH SOL (`console com2`) or HPE iLO VSP, proves that a shell interprets a random nonce, sends one single-line command, and captures its output plus exit code. It defaults to `dry_run=true`, which checks configuration without connecting. Execution requires both `dry_run=false` and `confirm_command` exactly equal to `command`.
Every host result reports `command_sent`, `result_confirmed`, `retry_safe`, transport, phase, exit code, bounded output, and truncation. Never repeat a `command_sent=true` result whose completion is unknown. `retry_console_operation_failures` selects only hosts proven not to have received the previous command. Use `start_console_command_batch` and poll `get_operation` for fleet commands that could exceed an MCP client timeout. Completed operation records aggregate `remote_state`, `outcome_unknown`, and `retry_safe` across their host results. Operation records live only in the MCP server process; after a restart, completion is unknown and mutating work must not be blindly retried.
VNC remains a visual fallback. `capture_console_screen` sends no input and returns PNG `ImageContent` plus a short-lived `input_confirmation_token`. Before every command, inspect a fresh token-producing image and confirm a focused shell, then pass that one-use token as `confirmation_token` to `run_console_command`. The command is displayed through a restricted `less` pager; navigate it with `console_pager_action`. If pager tracking expires, `get_console_session_status` reports remote state as unknown: make and inspect a new post-expiry capture, then pass its token to `console_pager_action` for one recovery, quit, interrupt, or visually justified abandon action. A VNC send or capture failure can leave partial text or an unknown command outcome, which is returned explicitly rather than retried.
VNC commands need POSIX `sh` and `less`. Console text is visible and may enter shell history, so never include passwords or tokens. Dell iDRAC VNC SSL encryption requires an external tunnel; the tools do not weaken BMC security settings.
### Persistent Network Inventory
Call `collect_network_inventory(server_ids, transport="auto", save=true)` to run short read-only Linux probes over SOL/VSP. It captures `ip`, sysfs carrier and physical-port data, `ethtool`, PCI vendor/model details, DMI identity, routes, addresses, and optional LLDP neighbors. It compares OS identity with Redfish and configured serial/MAC evidence before replacing a snapshot. Only verified identity is persisted; mismatched and unverified collections are returned as evidence but remain unsaved. For large sets, use `start_network_inventory_collection` and poll `get_operation`.
If serial collection cannot prove a shell, the result says whether visually guarded VNC fallback is available. The tool does not treat OCR as authoritative data. `get_network_hardware` is a separate read-only Redfish fallback for firmware-visible Ethernet interfaces, adapters, physical ports, and device functions; keep its evidence distinct from Linux interface names and carrier state.
The latest validated snapshots live under `network_inventory/hosts/<server_id>.yaml`. `save_network_inventory` and `save_network_inventories` support explicitly supplied structured observations, reject secrets and older timestamps by default, and write atomically.
Use these MCP tools for later retrieval:
- `get_network_inventory(server_id)` returns one complete host document.
- `list_network_inventories()` returns per-host counts of interfaces, active links, and addresses.
- `search_network_inventory(...)` combines paginated filters for `mac`, interface-name substring, `link_up`, exact IP or subnet, vendor substring, exact PCI address, and server ID.
- `validate_network_inventories(...)` reports missing, stale, malformed, duplicate-MAC, and host-identity problems.
- `export_network_inventory(...)` atomically produces one YAML or JSON file with connected-interface, MAC, IP, and separate BMC-MAC indexes.
Examples:
```text
search_network_inventory(mac="b4:96:91:c8:aa:28")
search_network_inventory(link_up=true)
search_network_inventory(ip="fe80::/64", vendor="Intel")
search_network_inventory(interface="ens1", server_id="bmc18-live")
validate_network_inventories(server_ids=["srv-dell-01", "srv-hpe-02"])
export_network_inventory(format="yaml", collection="rack-14")
```
The YAML remains directly searchable without MCP:
```bash
rg -l 'mac_address: b4:96:91:c8:aa:28' network_inventory/hosts
```
## Usage
Once the MCP server is running, your AI assistant will discover the Redfish tools automatically. You can ask it to perform tasks naturally:
- "List all servers in lab-a"
- "What is the power state of srv-dell-01?"
- "Get a hardware inventory for all servers with the 'gpu' tag"
- "Mount the Ubuntu ISO to srv-hpe-02 and boot from it once"
- "Update the firmware on srv-dell-01 using this URL: http://..."
- "Show me the MAC address table on lab1-switch"
- "Run 'show lldp neighbors' on the Junos switch"
- "Run 'show interface status' on the Dell OS10 switch"
- "Dry-run these Dell OS10 configuration commands on both switches, then run the unchanged confirmed plan"
- "Capture the console screen for srv-dell-01 and explain what is happening"
- "Run `journalctl -b` on the console, inspect every page, and tell me why boot failed"
- "Dry-run `systemctl restart NetworkManager` for these hosts over SOL, then execute it only on the confirmed targets"
- "Collect and save network data for every host tagged rack-14, then export its connected-MAC index"
- "Save this host's network inventory, then show every connected Intel interface across all saved hosts"
> **Note on caching:** `get_firmware_inventory`, `get_hardware_overview`, and `get_system_info` cache their responses in memory to reduce BMC load. If results look stale after a hardware change, ask the assistant to run `clear_server_cache` for the affected servers. TTL values are configurable in `global_config.yaml`.