Content
# beszel-mcp
A [Model Context Protocol (MCP)](https://modelcontextprotocol.io) server for [Beszel](https://beszel.dev) — the lightweight server monitoring platform. Query your servers' health, metrics, containers, and alerts directly from Claude or any MCP-compatible client.
---
## Features
| Tool | Description |
| ------------------------ | --------------------------------------------------------------- |
| `list_systems` | All monitored servers with status, CPU/memory/disk %, uptime |
| `search_systems` | Filter servers by name, host, status (PocketBase filter syntax) |
| `get_system_stats` | Detailed CPU, RAM, swap, disk I/O, network, temperatures |
| `list_docker_containers` | Docker/Podman containers — CPU, memory, health, network |
| `list_alerts` | Active (triggered) alerts, or all configured alert rules |
---
## Prerequisites
- Go 1.22+
- A running [Beszel hub](https://beszel.dev/guide/getting-started)
- A Beszel user account (email + password)
---
## Installation
```bash
git clone https://github.com/yourusername/beszel-mcp
cd beszel-mcp
go mod tidy
go build -o beszel-mcp .
```
---
## Configuration
The server is configured entirely via environment variables:
| Variable | Required | Description |
| ----------------- | -------- | -------------------------------------------- |
| `BESZEL_URL` | ✅ | Beszel hub URL, e.g. `http://localhost:8090` |
| `BESZEL_EMAIL` | ✅ | Beszel user email |
| `BESZEL_PASSWORD` | ✅ | Beszel user password |
> **Tip:** Admin accounts can see all systems; regular users only see systems they own.
---
## Claude Desktop Setup
Add the following to your `claude_desktop_config.json`:
**macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
**Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
**Linux:** `~/.config/Claude/claude_desktop_config.json`
```json
{
"mcpServers": {
"beszel": {
"command": "/absolute/path/to/beszel-mcp",
"env": {
"BESZEL_URL": "http://localhost:8090",
"BESZEL_EMAIL": "your@email.com",
"BESZEL_PASSWORD": "yourpassword"
}
}
}
}
```
Restart Claude Desktop. You should see the Beszel tools available in the tools menu.
---
## Claude Code / Other MCP Clients
Run directly:
```bash
BESZEL_URL=http://localhost:8090 \
BESZEL_EMAIL=your@email.com \
BESZEL_PASSWORD=yourpassword \
./beszel-mcp
```
Or with environment file:
```bash
# .env
BESZEL_URL=http://localhost:8090
BESZEL_EMAIL=your@email.com
BESZEL_PASSWORD=yourpassword
```
```bash
env $(cat .env | xargs) ./beszel-mcp
```
---
## Example Prompts
Once connected to Claude, try these:
- _"List all my servers and their current status"_
- _"Which servers are down right now?"_
- _"Show me the CPU and memory stats for my prod-web server"_
- _"List all Docker containers on system `abc123xyz`"_
- _"Are there any active alerts I should know about?"_
- _"Find all servers with 'nginx' in the name"_
- _"Which servers have status down or paused?"_
---
## Tool Reference
### `list_systems`
Lists all systems accessible to the authenticated user.
**Parameters:**
- `status_filter` *(optional)* — `"up"`, `"down"`, `"paused"`, or `"pending"`
**Example output:**
```
Found 3 system(s):
### ✅ prod-web
ID: abc123xyz
Host: 192.168.1.10:45876
Status: up
OS: Linux
Agent: v0.18.6
CPU: 12.3%
Memory: 45.1%
Disk: 61.0%
Load: 0.85 / 0.72 / 0.68
Uptime: 14d 6h 22m
```
---
### `search_systems`
Filter systems using [PocketBase filter syntax](https://pocketbase.io/docs/api-rules-and-filters/).
**Parameters:**
- `filter` *(required)* — Filter expression
**Filter examples:**
| Goal | Filter |
| ------------------- | ---------------------------------- |
| Name contains "web" | `name~"web"` |
| Exact name match | `name="prod-db"` |
| Specific status | `status="down"` |
| Host in subnet | `host~"10.0.0"` |
| Down or paused | `status="down"\|\|status="paused"` |
---
### `get_system_stats`
Detailed metrics for a single system.
**Parameters:**
- `system_id` *(required)* — System record ID
- `resolution` *(optional)* — Data granularity:
- `"1m"` — most recent ~1 hour of 1-minute samples
- `"10m"` — last ~12 hours *(default)*
- `"20m"` — last ~24 hours
- `"120m"` — last ~7 days
- `"480m"` — last ~30 days
---
### `list_docker_containers`
Lists Docker/Podman containers.
**Parameters:**
- `system_id` *(optional)* — Limit to one system; omit for all systems
**Columns:** Name, CPU%, Memory (GB), Network (bytes/s), Health, Image
---
### `list_alerts`
Shows alert rules and their triggered state.
**Parameters:**
- `all` *(optional, bool)* — `true` = show all rules; `false` (default) = only triggered
---
## Architecture
```
beszel-mcp/
├── main.go # Entry point, env config, server bootstrap
├── go.mod
├── internal/
│ ├── client/
│ │ └── beszel.go # PocketBase REST client, auth token cache
│ └── tools/
│ └── tools.go # MCP tool definitions and handlers
└── README.md
```
The client automatically handles JWT authentication and token refresh. Tokens are cached in-memory and refreshed proactively before expiry.
---
## Security Notes
- Credentials are passed via environment variables, never hardcoded
- The JWT token is stored in memory only; never written to disk
- Use a dedicated read-only Beszel user for the MCP server where possible
- If your Beszel instance is behind a reverse proxy with TLS, use `https://` in `BESZEL_URL`
---
## License
MIT