Plutus MCP Server
by Thefrizzy1
README.md
# Plutus โ MCP Manager
A single self-hosted **Model Context Protocol** server for a homelab, with a
full web app to configure it, watch its health, run agents, and hand ready-made
configs to any MCP client. ~193 tools across media, photos, home automation,
productivity, infrastructure, and public APIs โ all behind one endpoint.
- **MCP endpoint:** `http://<host>:8765/mcp` (streamable HTTP; `/sse` also served)
- **Web app:** `http://<host>:8766/app` (HTTP Basic auth; `/` and `/ui` redirect here)
> ๐ **Full docs:** [Architecture](docs/ARCHITECTURE.md) ยท
> [Security](docs/SECURITY.md) ยท [Operations](docs/OPERATIONS.md) ยท
> [Configuration](docs/CONFIGURATION.md) ยท [Agents & Scheduler](docs/AGENTS.md) ยท
> [Testing](docs/TESTING.md) ยท [Changelog](docs/CHANGELOG.md) ยท
> [Contributing](docs/CONTRIBUTING.md)
---
## What it is
One MCP server exposes every homelab service through a single, authenticated
endpoint, so any MCP client (Claude Desktop/Code, Cursor, VS Code, n8n, โฆ) can
drive your whole stack. The web app is a React desktop-style console (Vite +
React 19 + Tailwind 4 + lucide) served at `/app`, built into the image by a
multi-stage Docker build. It's the control centre: connections, health, agents,
files, settings, and a token-optimising tool slicer.
## The web app at a glance
| Section | What it does |
|---|---|
| **Dashboard** | Health overview โ connection counts by status, tools, capabilities, recent tool runs. Ignored connections are excluded from the stats. |
| **Connections** | The core management surface (the old *Integrations* page is folded in here). One row per service with its icon, category, tool count, web address, and a traffic-light status. Configure, test, hide, and browse the catalog from here. |
| **Discover** | Scan a LAN host for known services and **configure them straight away**, or point the **API Discovery** wizard at any OpenAPI/FastAPI service to read its endpoints and add it as a connection. |
| **Slicer** | Preview and shrink the tool manifest exposed to clients by intent (e.g. `calendar tasks files`). |
| **Agents** | Launch, schedule, and monitor headless **Claude Code** agents that operate Plutus's own tools. Usage stats, live console, per-run permissions. |
| **AI Builder** | Describe an agent in plain language; Claude drafts its goal/prompt; review and launch. |
| **Files** | Browse the **internal research library** the agents write to, plus any mounted SMB/NAS shares. Preview, download, delete (path-confined, secrets redacted). |
| **Settings** | MCP endpoint & bearer token, client-config export, custom integrations, tool-category exposure, defaults, UI credentials, reset. |
### Connections โ configure, test, manage
- **Icons + web address** per service, pulled from the registry and your live `.env`.
- **Inline Configure**: a form built from each service's env fields (URL, API key,
โฆ). Secrets are masked โ leave a secret blank to keep the current value.
- **Two-stage testing** with a tri-state light:
- **Test** = HTTP reachability probe.
- **Try** = actually calls the service's tools and checks they return data.
- ๐ข green = probe + tools OK ยท ๐ orange = reachable but tools failing (or not
yet tool-tested) ยท ๐ด red = unconfigured / unreachable.
- **Ignore / restore** a connection (๐ซ): ignored rows grey out and drop from the
Dashboard stats, the counts, and the agent connection picker.
- **Sortable columns** โ click a header to sort by it, click again to flip
ascending/descending (โฒ/โผ). Plus **Hide unconfigured** and **Show ignored**.
- **๏ผ Add** a custom connection, or **๐งฉ Catalog** to start from a popular service.
### Discover โ set it up in one flow
- **Network scan**: probe a host (Docker + common ports); each hit gets a
**Configure โ** button that saves the detected URL and opens the full form so
you can finish (add an API key) and land on Connections.
- **API Discovery (OpenAPI / FastAPI)**: enter a base URL; Plutus finds the spec
(`/openapi.json`, `/swagger.json`, `/v3/api-docs`, โฆ), lists every endpoint
(method, path, params), and can save it as a connection.
## Install
**Recommended โ pull the pre-built image:**
```bash
cp .env.example .env # set UI_PASSWORD; fill in the services you use
chmod 600 .env
docker compose pull && docker compose up -d
```
Uses `ghcr.io/thefrizzy1/mcp-manager:latest`, published by GitHub Actions **only
after the test suite passes** (see [CI](#ci)). Update later with the same
`pull && up -d`.
**Alternative โ build from source (e.g. a git-context compose):**
```bash
docker compose build --no-cache && docker compose up -d --force-recreate
```
`docker compose up --build` does the same for a local checkout. After deploy,
confirm the running version in **Settings โ About** (or
`docker exec plutus-mcp cat core/version_info.py`).
## Tools included
| Service | Tools |
|---|---|
| Jellyfin | search, recently added |
| Sonarr | search, list, add, queue, calendar, missing |
| Radarr / Lidarr | search, list, add, queue |
| Jellyseerr | request, list requests |
| qBittorrent | list, pause, resume, delete |
| Habitica | tasks, stats, score, add todo, add/delete task |
| Nextcloud | calendars, events, tasks, notes, contacts, files |
| Home Assistant | states, search, call service, on/off |
| Immich | search, albums, memories, people |
| Docker / OMV | containers, logs, start/stop/restart; disk & system info |
| SSH / SMB | allowlisted remote commands; share browse/manage/mount |
| Ntfy | send notifications |
| Filesystem | list, read (secret-redacted), search, write, move |
| ComfyUI / fal.ai | image generation & workflow control |
| Public APIs | weather, maps, web/Google search, finance, trivia, Wikipedia, โฆ |
Custom services (any HTTP API, or one discovered via OpenAPI) are added from the
Connections page and stored in `data/custom_integrations.json`.
## Connect an MCP client
**Settings โ Connect a client** generates and downloads a ready-to-use config
for Claude Desktop, Claude Code, Cursor, VS Code, Cline, Windsurf, ChatGPT/OpenAI,
LM Studio, Open WebUI, or n8n โ pre-filled with your URL and (optionally) a Bearer
token. A **Test connection** button verifies it first.
Claude Desktop bridges to the remote endpoint via `mcp-remote`:
```json
{
"mcpServers": {
"plutus": {
"command": "npx",
"args": ["mcp-remote", "http://<host>:8765/mcp", "--allow-http"]
}
}
}
```
Claude Code, Cursor, VS Code, etc. connect to `http://<host>:8765/mcp` directly โ
let the exporter emit the exact format for each.
## Agents & scheduler
The **Agents** workspace runs a headless **Claude Code** agent that operates
Plutus's own ~193 tools โ e.g. *"find stuck \*arr queues and restart unhealthy
containers"* or a nightly research playbook โ with a live console, cost tracking,
and a serial run queue.
- **Launch wizard**: name, model, schedule (run now / daily / weekly / cron),
**write / publish switches**, and a **per-connection allow-list** of exactly
which services the agent may touch.
- **Capability switches** (enforced via Claude Code `--disallowedTools`):
**write** off = a read-only audit posture; **publish** off (the default)
blocks outward actions โ email, ntfy, webhooks, public GitHub issues/PRs,
share links โ even when write is on.
- **Per-connection ACL**: unchecked homelab connections are blocked for that run;
web/search/weather/file utilities always stay available so research still
works. Both ad-hoc **and scheduled** runs carry their own permission + ACL โ
running one "all tools" agent never silently escalates your schedules.
- **Usage**: runs-today vs a daily cap, remaining budget, all-time cost, queue
depth, and account/auth state.
- **Sign in with your subscription** (session/OAuth token, not an API key):
Settings โ paste a `claude setup-token` token. `ANTHROPIC_API_KEY` stays a
compose-only opt-in.
Schedule agent prompts, saved playbooks, or individual tool calls on a cron. See
[docs/AGENTS.md](docs/AGENTS.md).
## Security (summary)
- Web UI behind HTTP Basic auth (+ login lockout); app-wide CSRF Origin-check on
every mutating request.
- Optional MCP Bearer auth (`MCP_REQUIRE_BEARER=true`), applied live without a
restart.
- Docker writes off by default; SSH hosts read-only by default; filesystem
confined to `FILESYSTEM_ALLOWED_PATHS` (symlink/`..`-resolved, boundary-aware)
plus the internal library.
- Secrets in files/errors are redacted by default; the Configure form never
returns stored secret values; `web_fetch` has an SSRF guard.
- Agents run with a real permission model, not all-or-nothing (see above).
- **Keep ports 8765/8766 off the public internet โ LAN/Tailscale only.**
Full model, threat analysis, and hardening checklist: [docs/SECURITY.md](docs/SECURITY.md).
## Health monitoring
- **Connections โ Test all** runs every service check and shows the full markdown
health report.
- `POST /api/v1/health/regression-check?notify=1` runs the tool batch, diffs
against a saved baseline, and ntfy-alerts on tools that worked before and fail
now. Schedule it via the Agents scheduler, cron, or n8n โ see
[docs/OPERATIONS.md](docs/OPERATIONS.md#3-health--monitoring).
## Remote access via Tailscale (optional)
```bash
tailscale serve --bg --https=443 http://localhost:8766 # web app
```
Set `PUBLIC_MCP_BASE=https://<name>.<ts-net>` in `.env` so the client exporter
emits HTTPS configs. Connect MCP clients to `https://<name>.<ts-net>/mcp`.
## CI
`.github/workflows/docker-publish.yml` runs on every push and pull request:
installs deps, `node --check`s the SPA bundle, runs `pyflakes`, and runs the
offline `pytest` suite. The image build **depends on the tests passing**, so a
broken commit never publishes; pull requests are tested but not published.
## Development
```bash
pip install -r requirements.txt -r requirements-dev.txt
python -m pytest # offline backend suite (no network)
# Frontend (React app in ui/web/):
npm --prefix ui/web install
npm --prefix ui/web run build # -> ui/static/dist (served at /app)
npm --prefix ui/web run dev # dev server on :5173, proxies /api to :8766
```
The UI lives in `ui/web/` (Vite). The build outputs hashed assets to
`ui/static/dist`; FastAPI serves them at `/app` (falling back to the legacy SPA
only if `dist` is absent). No manual cache-busting โ Vite hashes filenames. See
[docs/CONTRIBUTING.md](docs/CONTRIBUTING.md).
**Updating is non-destructive:** `docker compose pull && docker compose up -d`
preserves your settings, connections, profiles, and keys (data/, config/ and the
mounted `.env` persist).
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues