From 8600c63bab4a1c902f067e22de10e2c97dce876b Mon Sep 17 00:00:00 2001 From: Thomas Camlong Date: Tue, 16 Jun 2026 15:09:36 +0200 Subject: [PATCH] feat(beszel): expose Beszel systems, alerts, and stats via MCP Register beszelRouter in the MCP server with .meta({ mcp: enabled }) on getSystems, getAlerts, and getSystemStats procedures. AI assistants can now query Beszel-monitored systems, view alerts, and fetch historical metrics through the MCP protocol. Ref #5968 --- apps/docs/docs/management/mcp.mdx | 2 ++ .../src/app/api/mcp/[transport]/route.ts | 2 ++ packages/api/src/mcp.ts | 2 ++ packages/api/src/router/widgets/beszel.ts | 21 +++++++++++++++++++ 4 files changed, 27 insertions(+) diff --git a/apps/docs/docs/management/mcp.mdx b/apps/docs/docs/management/mcp.mdx index 66e0fca27..5317ecce2 100644 --- a/apps/docs/docs/management/mcp.mdx +++ b/apps/docs/docs/management/mcp.mdx @@ -130,6 +130,7 @@ Homarr exposes 50+ tools organized by namespace. Each tool is either a **query** | ------------------ | -------------------------------------------------------- | ---------- | | `app` | List all apps, get app by ID, create/update/delete app | GET + POST | | `apiKeys` | List API keys | GET | +| `beszel` | Systems status, alerts, historical system metrics | GET | | `board` | List boards, get board by ID, create/update/delete board | GET + POST | | `docker` | List containers, inspect container, start/stop/restart | GET + POST | | `icon` | Search icons | GET | @@ -162,3 +163,4 @@ The tools table on the MCP tab is dynamically generated - it always reflects the - **"Create a new app pointing to my Grafana instance"** - AI creates an app with the correct icon and URL - **"How many users are on my Homarr instance?"** - AI lists all users (admin only) - **"Toggle Pi-hole blocking for 5 minutes"** - AI interacts with DNS controls +- **"How are my servers doing?"** - AI fetches Beszel system stats including CPU, memory, disk, and alerts diff --git a/apps/nextjs/src/app/api/mcp/[transport]/route.ts b/apps/nextjs/src/app/api/mcp/[transport]/route.ts index 2cfcfbb24..0611a5a57 100644 --- a/apps/nextjs/src/app/api/mcp/[transport]/route.ts +++ b/apps/nextjs/src/app/api/mcp/[transport]/route.ts @@ -148,6 +148,8 @@ If \`hasUseAccess\` is false, the API key owner lacks permission for that integr **"Check server health"** → Use \`healthMonitoring_getSystemHealthStatus\` for NAS/server metrics or \`healthMonitoring_getClusterHealthStatus\` for Proxmox clusters. +**"Check Beszel systems"** → Use \`beszel_getSystems\` to list all monitored systems with CPU/memory/disk/network status. Use \`beszel_getAlerts\` for active alerts and history. Use \`beszel_getSystemStats\` for historical metrics of a specific system (requires systemId from \`beszel_getSystems\`). + **"Manage Docker containers"** → Use \`docker_getContainers\` to list containers with status/CPU/memory, then \`docker_startAll\`/\`docker_stopAll\`/\`docker_restartAll\` with container IDs. **"Control smart home"** → Use \`smartHome_entityState\` to check a Home Assistant entity, \`smartHome_switchEntity\` to toggle it, or \`smartHome_executeAutomation\` to trigger an automation. diff --git a/packages/api/src/mcp.ts b/packages/api/src/mcp.ts index 299a88e0b..1a08d37f1 100644 --- a/packages/api/src/mcp.ts +++ b/packages/api/src/mcp.ts @@ -16,6 +16,7 @@ import { healthMonitoringRouter } from "./router/widgets/health-monitoring"; import { mediaRequestsRouter } from "./router/widgets/media-requests"; import { mediaServerRouter } from "./router/widgets/media-server"; import { smartHomeRouter } from "./router/widgets/smart-home"; +import { beszelRouter } from "./router/widgets/beszel"; export const mcpRouter = createTRPCRouter({ app: appRouterForApps, @@ -26,6 +27,7 @@ export const mcpRouter = createTRPCRouter({ info: infoRouter, integration: integrationRouter, invite: inviteRouter, + beszel: beszelRouter, calendar: calendarRouter, dnsHole: dnsHoleRouter, downloads: downloadsRouter, diff --git a/packages/api/src/router/widgets/beszel.ts b/packages/api/src/router/widgets/beszel.ts index 036558ac1..a20182240 100644 --- a/packages/api/src/router/widgets/beszel.ts +++ b/packages/api/src/router/widgets/beszel.ts @@ -15,6 +15,13 @@ import { createTRPCRouter, publicProcedure } from "../../trpc"; export const beszelRouter = createTRPCRouter({ getSystems: publicProcedure + .meta({ + mcp: { + enabled: true, + description: + "Get all Beszel-monitored systems with CPU, memory, disk, GPU, network, temperature, and status. REQUIRED: integrationIds (array of Beszel integration IDs from integration_all)", + }, + }) .concat(createManyIntegrationMiddleware("query", "beszel", "mock")) .query(async ({ ctx }) => { const results = await Promise.all( @@ -60,6 +67,13 @@ export const beszelRouter = createTRPCRouter({ }), getAlerts: publicProcedure + .meta({ + mcp: { + enabled: true, + description: + "Get Beszel alerts and optional alert history for all monitored systems. REQUIRED: integrationIds (array of Beszel integration IDs from integration_all). OPTIONAL: includeHistory (default true), maxHistoryItems (default 10)", + }, + }) .concat(createManyIntegrationMiddleware("query", "beszel", "mock")) .input( z.object({ @@ -129,6 +143,13 @@ export const beszelRouter = createTRPCRouter({ }), getSystemStats: publicProcedure + .meta({ + mcp: { + enabled: true, + description: + "Get historical Beszel system metrics (CPU, memory, disk, network, temperature) and optional Docker container stats. REQUIRED: integrationIds (array of Beszel integration IDs from integration_all), systemId (from beszel_getSystems). OPTIONAL: timePeriod (1h/12h/24h/1w/30d, default 1h), includeDocker (default true)", + }, + }) .concat(createManyIntegrationMiddleware("query", "beszel", "mock")) .input( z.object({