6 Commits

Author SHA1 Message Date
Jacob Magar
207b68cd8c chore: initialize beads + lavra project config (v1.1.5)
- bd init: Dolt-backed issue tracker, prefix unraid-mcp-<hash>
- .lavra/config/project-setup.md: python stack, 4 review agents
- .lavra/config/codebase-profile.md: stack/arch/conventions profile
- .gitignore: add lavra session-state and beads entries
- CLAUDE.md: beads workflow integration block

Co-Authored-By: Claude <noreply@anthropic.com>
2026-03-27 21:30:12 -04:00
Jacob Magar
1c8a81786c bd init: initialize beads issue tracking 2026-03-27 20:49:51 -04:00
Jacob Magar
abb71f17ff chore: rebrand plugin to unRAID, expand description with full action reference (v1.1.4)
- Add displayName "unRAID" to plugin.json and marketplace.json
- Expand description to list all 15 action domains and 107 subactions
- Mark destructive subactions with * in description
- Bump version 1.1.3 → 1.1.4

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-03-25 00:18:16 -04:00
Jacob Magar
87cd5e5193 docs: expand plugin README with full tool/action/subaction reference 2026-03-24 23:35:54 -04:00
Jacob Magar
2f9decdac9 chore: sync plugin description and marketplace version to 1.1.3 2026-03-24 23:33:48 -04:00
Jacob Magar
8a43b2535a feat: Google OAuth, API key auth, consolidated tool, docs overhaul (v1.1.3)
Merges feat/google-oauth into main.

Highlights:
- Consolidated 15 individual tools into single `unraid` tool with action/subaction routing
- Added API key bearer token authentication for HTTP transport
- Added Google OAuth via FastMCP GoogleProvider (subsequently removed in favor of external gateway pattern)
- Comprehensive security hardening: path traversal fixes, timing-safe auth, traceback leak prevention
- CI pipeline: lint, typecheck, test, version-sync, audit
- CHANGELOG.md, AUTHENTICATION.md, full PR review comment resolution
- Version: 1.0.0 → 1.1.3 across this branch

Co-Authored-By: Claude <noreply@anthropic.com>
2026-03-24 23:26:52 -04:00
19 changed files with 738 additions and 59 deletions

72
.beads/.gitignore vendored Normal file
View File

@@ -0,0 +1,72 @@
# Dolt database (managed by Dolt, not git)
dolt/
dolt-access.lock
# Runtime files
bd.sock
bd.sock.startlock
sync-state.json
last-touched
.exclusive-lock
# Daemon runtime (lock, log, pid)
daemon.*
# Interactions log (runtime, not versioned)
interactions.jsonl
# Push state (runtime, per-machine)
push-state.json
# Lock files (various runtime locks)
*.lock
# Credential key (encryption key for federation peer auth — never commit)
.beads-credential-key
# Local version tracking (prevents upgrade notification spam after git ops)
.local_version
# Worktree redirect file (contains relative path to main repo's .beads/)
# Must not be committed as paths would be wrong in other clones
redirect
# Sync state (local-only, per-machine)
# These files are machine-specific and should not be shared across clones
.sync.lock
export-state/
# Ephemeral store (SQLite - wisps/molecules, intentionally not versioned)
ephemeral.sqlite3
ephemeral.sqlite3-journal
ephemeral.sqlite3-wal
ephemeral.sqlite3-shm
# Dolt server management (auto-started by bd)
dolt-server.pid
dolt-server.log
dolt-server.lock
dolt-server.port
dolt-server.activity
# Corrupt backup directories (created by bd doctor --fix recovery)
*.corrupt.backup/
# Backup data (auto-exported JSONL, local-only)
backup/
# Per-project environment file (Dolt connection config, GH#2520)
.env
# Legacy files (from pre-Dolt versions)
*.db
*.db?*
*.db-journal
*.db-wal
*.db-shm
db.sqlite
bd.db
# NOTE: Do NOT add negation patterns here.
# They would override fork protection in .git/info/exclude.
# Config files (metadata.json, config.yaml) are tracked by git by default
# since no pattern above ignores them.

81
.beads/README.md Normal file
View File

@@ -0,0 +1,81 @@
# Beads - AI-Native Issue Tracking
Welcome to Beads! This repository uses **Beads** for issue tracking - a modern, AI-native tool designed to live directly in your codebase alongside your code.
## What is Beads?
Beads is issue tracking that lives in your repo, making it perfect for AI coding agents and developers who want their issues close to their code. No web UI required - everything works through the CLI and integrates seamlessly with git.
**Learn more:** [github.com/steveyegge/beads](https://github.com/steveyegge/beads)
## Quick Start
### Essential Commands
```bash
# Create new issues
bd create "Add user authentication"
# View all issues
bd list
# View issue details
bd show <issue-id>
# Update issue status
bd update <issue-id> --claim
bd update <issue-id> --status done
# Sync with Dolt remote
bd dolt push
```
### Working with Issues
Issues in Beads are:
- **Git-native**: Stored in Dolt database with version control and branching
- **AI-friendly**: CLI-first design works perfectly with AI coding agents
- **Branch-aware**: Issues can follow your branch workflow
- **Always in sync**: Auto-syncs with your commits
## Why Beads?
**AI-Native Design**
- Built specifically for AI-assisted development workflows
- CLI-first interface works seamlessly with AI coding agents
- No context switching to web UIs
🚀 **Developer Focused**
- Issues live in your repo, right next to your code
- Works offline, syncs when you push
- Fast, lightweight, and stays out of your way
🔧 **Git Integration**
- Automatic sync with git commits
- Branch-aware issue tracking
- Dolt-native three-way merge resolution
## Get Started with Beads
Try Beads in your own projects:
```bash
# Install Beads
curl -sSL https://raw.githubusercontent.com/steveyegge/beads/main/scripts/install.sh | bash
# Initialize in your repo
bd init
# Create your first issue
bd create "Try out Beads"
```
## Learn More
- **Documentation**: [github.com/steveyegge/beads/docs](https://github.com/steveyegge/beads/tree/main/docs)
- **Quick Start Guide**: Run `bd quickstart`
- **Examples**: [github.com/steveyegge/beads/examples](https://github.com/steveyegge/beads/tree/main/examples)
---
*Beads: Issue tracking that moves at the speed of thought*

54
.beads/config.yaml Normal file
View File

@@ -0,0 +1,54 @@
# Beads Configuration File
# This file configures default behavior for all bd commands in this repository
# All settings can also be set via environment variables (BD_* prefix)
# or overridden with command-line flags
# Issue prefix for this repository (used by bd init)
# If not set, bd init will auto-detect from directory name
# Example: issue-prefix: "myproject" creates issues like "myproject-1", "myproject-2", etc.
# issue-prefix: ""
# Use no-db mode: JSONL-only, no Dolt database
# When true, bd will use .beads/issues.jsonl as the source of truth
# no-db: false
# Enable JSON output by default
# json: false
# Feedback title formatting for mutating commands (create/update/close/dep/edit)
# 0 = hide titles, N > 0 = truncate to N characters
# output:
# title-length: 255
# Default actor for audit trails (overridden by BEADS_ACTOR or --actor)
# actor: ""
# Export events (audit trail) to .beads/events.jsonl on each flush/sync
# When enabled, new events are appended incrementally using a high-water mark.
# Use 'bd export --events' to trigger manually regardless of this setting.
# events-export: false
# Multi-repo configuration (experimental - bd-307)
# Allows hydrating from multiple repositories and routing writes to the correct database
# repos:
# primary: "." # Primary repo (where this database lives)
# additional: # Additional repos to hydrate from (read-only)
# - ~/beads-planning # Personal planning repo
# - ~/work-planning # Work planning repo
# JSONL backup (periodic export for off-machine recovery)
# Auto-enabled when a git remote exists. Override explicitly:
# backup:
# enabled: false # Disable auto-backup entirely
# interval: 15m # Minimum time between auto-exports
# git-push: false # Disable git push (export locally only)
# git-repo: "" # Separate git repo for backups (default: project repo)
# Integration settings (access with 'bd config get/set')
# These are stored in the database, not in this file:
# - jira.url
# - jira.project
# - linear.url
# - linear.api-key
# - github.org
# - github.repo

24
.beads/hooks/post-checkout Executable file
View File

@@ -0,0 +1,24 @@
#!/usr/bin/env sh
# --- BEGIN BEADS INTEGRATION v0.62.0 ---
# This section is managed by beads. Do not remove these markers.
if command -v bd >/dev/null 2>&1; then
export BD_GIT_HOOK=1
_bd_timeout=${BEADS_HOOK_TIMEOUT:-300}
if command -v timeout >/dev/null 2>&1; then
timeout "$_bd_timeout" bd hooks run post-checkout "$@"
_bd_exit=$?
if [ $_bd_exit -eq 124 ]; then
echo >&2 "beads: hook 'post-checkout' timed out after ${_bd_timeout}s — continuing without beads"
_bd_exit=0
fi
else
bd hooks run post-checkout "$@"
_bd_exit=$?
fi
if [ $_bd_exit -eq 3 ]; then
echo >&2 "beads: database not initialized — skipping hook 'post-checkout'"
_bd_exit=0
fi
if [ $_bd_exit -ne 0 ]; then exit $_bd_exit; fi
fi
# --- END BEADS INTEGRATION v0.62.0 ---

24
.beads/hooks/post-merge Executable file
View File

@@ -0,0 +1,24 @@
#!/usr/bin/env sh
# --- BEGIN BEADS INTEGRATION v0.62.0 ---
# This section is managed by beads. Do not remove these markers.
if command -v bd >/dev/null 2>&1; then
export BD_GIT_HOOK=1
_bd_timeout=${BEADS_HOOK_TIMEOUT:-300}
if command -v timeout >/dev/null 2>&1; then
timeout "$_bd_timeout" bd hooks run post-merge "$@"
_bd_exit=$?
if [ $_bd_exit -eq 124 ]; then
echo >&2 "beads: hook 'post-merge' timed out after ${_bd_timeout}s — continuing without beads"
_bd_exit=0
fi
else
bd hooks run post-merge "$@"
_bd_exit=$?
fi
if [ $_bd_exit -eq 3 ]; then
echo >&2 "beads: database not initialized — skipping hook 'post-merge'"
_bd_exit=0
fi
if [ $_bd_exit -ne 0 ]; then exit $_bd_exit; fi
fi
# --- END BEADS INTEGRATION v0.62.0 ---

24
.beads/hooks/pre-commit Executable file
View File

@@ -0,0 +1,24 @@
#!/usr/bin/env sh
# --- BEGIN BEADS INTEGRATION v0.62.0 ---
# This section is managed by beads. Do not remove these markers.
if command -v bd >/dev/null 2>&1; then
export BD_GIT_HOOK=1
_bd_timeout=${BEADS_HOOK_TIMEOUT:-300}
if command -v timeout >/dev/null 2>&1; then
timeout "$_bd_timeout" bd hooks run pre-commit "$@"
_bd_exit=$?
if [ $_bd_exit -eq 124 ]; then
echo >&2 "beads: hook 'pre-commit' timed out after ${_bd_timeout}s — continuing without beads"
_bd_exit=0
fi
else
bd hooks run pre-commit "$@"
_bd_exit=$?
fi
if [ $_bd_exit -eq 3 ]; then
echo >&2 "beads: database not initialized — skipping hook 'pre-commit'"
_bd_exit=0
fi
if [ $_bd_exit -ne 0 ]; then exit $_bd_exit; fi
fi
# --- END BEADS INTEGRATION v0.62.0 ---

24
.beads/hooks/pre-push Executable file
View File

@@ -0,0 +1,24 @@
#!/usr/bin/env sh
# --- BEGIN BEADS INTEGRATION v0.62.0 ---
# This section is managed by beads. Do not remove these markers.
if command -v bd >/dev/null 2>&1; then
export BD_GIT_HOOK=1
_bd_timeout=${BEADS_HOOK_TIMEOUT:-300}
if command -v timeout >/dev/null 2>&1; then
timeout "$_bd_timeout" bd hooks run pre-push "$@"
_bd_exit=$?
if [ $_bd_exit -eq 124 ]; then
echo >&2 "beads: hook 'pre-push' timed out after ${_bd_timeout}s — continuing without beads"
_bd_exit=0
fi
else
bd hooks run pre-push "$@"
_bd_exit=$?
fi
if [ $_bd_exit -eq 3 ]; then
echo >&2 "beads: database not initialized — skipping hook 'pre-push'"
_bd_exit=0
fi
if [ $_bd_exit -ne 0 ]; then exit $_bd_exit; fi
fi
# --- END BEADS INTEGRATION v0.62.0 ---

24
.beads/hooks/prepare-commit-msg Executable file
View File

@@ -0,0 +1,24 @@
#!/usr/bin/env sh
# --- BEGIN BEADS INTEGRATION v0.62.0 ---
# This section is managed by beads. Do not remove these markers.
if command -v bd >/dev/null 2>&1; then
export BD_GIT_HOOK=1
_bd_timeout=${BEADS_HOOK_TIMEOUT:-300}
if command -v timeout >/dev/null 2>&1; then
timeout "$_bd_timeout" bd hooks run prepare-commit-msg "$@"
_bd_exit=$?
if [ $_bd_exit -eq 124 ]; then
echo >&2 "beads: hook 'prepare-commit-msg' timed out after ${_bd_timeout}s — continuing without beads"
_bd_exit=0
fi
else
bd hooks run prepare-commit-msg "$@"
_bd_exit=$?
fi
if [ $_bd_exit -eq 3 ]; then
echo >&2 "beads: database not initialized — skipping hook 'prepare-commit-msg'"
_bd_exit=0
fi
if [ $_bd_exit -ne 0 ]; then exit $_bd_exit; fi
fi
# --- END BEADS INTEGRATION v0.62.0 ---

7
.beads/metadata.json Normal file
View File

@@ -0,0 +1,7 @@
{
"database": "dolt",
"backend": "dolt",
"dolt_mode": "server",
"dolt_database": "unraid_mcp",
"project_id": "5bb31674-18f6-4968-8fd9-71a7ceceaa48"
}

View File

@@ -1,73 +1,239 @@
# Unraid MCP Marketplace # Unraid MCP Plugin
This directory contains the Claude Code marketplace configuration for the Unraid MCP server and skills. Query, monitor, and manage Unraid servers via GraphQL API using a single consolidated `unraid` tool with action+subaction routing.
**Version:** 1.1.3 | **Category:** Infrastructure | **Tags:** unraid, homelab, graphql, docker, virtualization
---
## Installation ## Installation
### From GitHub (Recommended)
```bash ```bash
# Add the marketplace
/plugin marketplace add jmagar/unraid-mcp /plugin marketplace add jmagar/unraid-mcp
# Install the Unraid skill
/plugin install unraid @unraid-mcp /plugin install unraid @unraid-mcp
``` ```
### From Local Path (Development) After install, configure credentials:
```bash
# Add local marketplace
/plugin marketplace add /path/to/unraid-mcp
# Install the plugin
/plugin install unraid @unraid-mcp
```
## Available Plugins
### unraid
Query and monitor Unraid servers via GraphQL API - array status, disk health, containers, VMs, system monitoring.
**Features:**
- 1 consolidated `unraid` tool with ~108 actions across 15 domains
- Real-time live subscriptions (CPU, memory, logs, array state, UPS)
- Disk health and temperature monitoring
- Docker container management
- VM status and control
- Log file access
- Network share information
- Notification management
- Plugin, rclone, API key, and OIDC management
**Version:** 1.1.2
**Category:** Infrastructure
**Tags:** unraid, monitoring, homelab, graphql, docker, virtualization
## Configuration
After installation, run setup to configure credentials interactively:
```python ```python
unraid(action="health", subaction="setup") unraid(action="health", subaction="setup")
``` ```
Credentials are stored at `~/.unraid-mcp/.env` automatically. Credentials are stored at `~/.unraid-mcp/.env`. Get an API key from **Unraid WebUI → Settings → Management Access → API Keys**.
**Getting an API Key:** ---
1. Open Unraid WebUI
2. Go to Settings → Management Access → API Keys
3. Click "Create" and select "Viewer" role (or appropriate roles for mutations)
4. Copy the generated API key
## Documentation ## Tools
- **Plugin Documentation:** See `skills/unraid/README.md` ### `unraid` — Primary Tool (107 subactions, 15 domains)
- **MCP Server Documentation:** See root `README.md`
- **API Reference:** See `skills/unraid/references/` Call as `unraid(action="<domain>", subaction="<operation>", [params])`.
#### `system` — Server Information (18 subactions)
| Subaction | Description |
|-----------|-------------|
| `overview` | Complete system summary (recommended starting point) |
| `server` | Hostname, version, uptime |
| `servers` | All known Unraid servers |
| `array` | Array status and disk list |
| `network` | Network interfaces and config |
| `registration` | License and registration status |
| `variables` | Environment variables |
| `metrics` | Real-time CPU, memory, I/O usage |
| `services` | Running services status |
| `display` | Display settings |
| `config` | System configuration |
| `online` | Quick online status check |
| `owner` | Server owner information |
| `settings` | User settings and preferences |
| `flash` | USB flash drive details |
| `ups_devices` | List all UPS devices |
| `ups_device` | Single UPS device (requires `device_id`) |
| `ups_config` | UPS configuration |
#### `health` — Diagnostics (4 subactions)
| Subaction | Description |
|-----------|-------------|
| `check` | Comprehensive health check — connectivity, array, disks, containers, VMs, resources |
| `test_connection` | Test API connectivity and authentication |
| `diagnose` | Detailed diagnostic report with troubleshooting recommendations |
| `setup` | Configure credentials interactively (stores to `~/.unraid-mcp/.env`) |
#### `array` — Array & Parity (13 subactions)
| Subaction | Description |
|-----------|-------------|
| `parity_status` | Current parity check progress and status |
| `parity_history` | Historical parity check results |
| `parity_start` | Start a parity check (requires `correct`) |
| `parity_pause` | Pause a running parity check |
| `parity_resume` | Resume a paused parity check |
| `parity_cancel` | Cancel a running parity check |
| `start_array` | Start the array |
| `stop_array` | ⚠️ Stop the array (requires `confirm=True`) |
| `add_disk` | Add a disk to the array (requires `slot`, `id`) |
| `remove_disk` | ⚠️ Remove a disk (requires `slot`, `confirm=True`) |
| `mount_disk` | Mount a disk |
| `unmount_disk` | Unmount a disk |
| `clear_disk_stats` | ⚠️ Clear disk statistics (requires `confirm=True`) |
#### `disk` — Storage & Logs (6 subactions)
| Subaction | Description |
|-----------|-------------|
| `shares` | List network shares |
| `disks` | All physical disks with health and temperatures |
| `disk_details` | Detailed info for a specific disk (requires `disk_id`) |
| `log_files` | List available log files |
| `logs` | Read log content (requires `log_path`; optional `tail_lines`) |
| `flash_backup` | ⚠️ Trigger a flash backup (requires `confirm=True`) |
#### `docker` — Containers (7 subactions)
| Subaction | Description |
|-----------|-------------|
| `list` | All containers with status, image, state |
| `details` | Single container details (requires container identifier) |
| `start` | Start a container (requires container identifier) |
| `stop` | Stop a container (requires container identifier) |
| `restart` | Restart a container (requires container identifier) |
| `networks` | List Docker networks |
| `network_details` | Details for a specific network (requires `network_id`) |
Container identification: name, ID, or partial name (fuzzy match).
#### `vm` — Virtual Machines (9 subactions)
| Subaction | Description |
|-----------|-------------|
| `list` | All VMs with state |
| `details` | Single VM details (requires `vm_id`) |
| `start` | Start a VM (requires `vm_id`) |
| `stop` | Gracefully stop a VM (requires `vm_id`) |
| `pause` | Pause a VM (requires `vm_id`) |
| `resume` | Resume a paused VM (requires `vm_id`) |
| `reboot` | Reboot a VM (requires `vm_id`) |
| `force_stop` | ⚠️ Force stop a VM (requires `vm_id`, `confirm=True`) |
| `reset` | ⚠️ Hard reset a VM (requires `vm_id`, `confirm=True`) |
#### `notification` — Notifications (12 subactions)
| Subaction | Description |
|-----------|-------------|
| `overview` | Notification counts (unread, archived by type) |
| `list` | List notifications (optional `filter`, `limit`, `offset`) |
| `create` | Create a notification (requires `title`, `subject`, `description`, `importance`) |
| `archive` | Archive a notification (requires `notification_id`) |
| `mark_unread` | Mark a notification as unread (requires `notification_id`) |
| `recalculate` | Recalculate notification counts |
| `archive_all` | Archive all unread notifications |
| `archive_many` | Archive multiple (requires `ids` list) |
| `unarchive_many` | Unarchive multiple (requires `ids` list) |
| `unarchive_all` | Unarchive all archived notifications |
| `delete` | ⚠️ Delete a notification (requires `notification_id`, `notification_type`, `confirm=True`) |
| `delete_archived` | ⚠️ Delete all archived (requires `confirm=True`) |
#### `key` — API Keys (7 subactions)
| Subaction | Description |
|-----------|-------------|
| `list` | All API keys |
| `get` | Single key details (requires `key_id`) |
| `create` | Create a new key (requires `name`; optional `roles`, `permissions`) |
| `update` | Update a key (requires `key_id`) |
| `delete` | ⚠️ Delete a key (requires `key_id`, `confirm=True`) |
| `add_role` | Add roles to a key (requires `key_id`, `roles`) |
| `remove_role` | Remove roles from a key (requires `key_id`, `roles`) |
#### `plugin` — Plugins (3 subactions)
| Subaction | Description |
|-----------|-------------|
| `list` | All installed plugins |
| `add` | Install plugins (requires `names` list) |
| `remove` | ⚠️ Uninstall plugins (requires `names` list, `confirm=True`) |
#### `rclone` — Cloud Storage (4 subactions)
| Subaction | Description |
|-----------|-------------|
| `list_remotes` | List configured rclone remotes |
| `config_form` | Get configuration form for a remote type |
| `create_remote` | Create a new remote (requires `name`, `provider_type`, `config_data`) |
| `delete_remote` | ⚠️ Delete a remote (requires `name`, `confirm=True`) |
#### `setting` — System Settings (2 subactions)
| Subaction | Description |
|-----------|-------------|
| `update` | Update system settings (requires `settings_input` object) |
| `configure_ups` | ⚠️ Configure UPS settings (requires `confirm=True`) |
#### `customization` — Theme & Appearance (5 subactions)
| Subaction | Description |
|-----------|-------------|
| `theme` | Current theme settings |
| `public_theme` | Public-facing theme |
| `is_initial_setup` | Check if initial setup is complete |
| `sso_enabled` | Check SSO status |
| `set_theme` | Update theme (requires theme parameters) |
#### `oidc` — SSO / OpenID Connect (5 subactions)
| Subaction | Description |
|-----------|-------------|
| `providers` | List configured OIDC providers |
| `provider` | Single provider details (requires `provider_id`) |
| `configuration` | OIDC configuration |
| `public_providers` | Public-facing provider list |
| `validate_session` | Validate current SSO session (requires `token`) |
#### `user` — Current User (1 subaction)
| Subaction | Description |
|-----------|-------------|
| `me` | Current authenticated user info |
#### `live` — Real-Time Subscriptions (11 subactions)
Persistent WebSocket connections. Returns `{"status": "connecting"}` on first call — retry momentarily.
| Subaction | Description |
|-----------|-------------|
| `cpu` | Live CPU utilization |
| `memory` | Live memory usage |
| `cpu_telemetry` | Detailed CPU telemetry |
| `array_state` | Live array state changes |
| `parity_progress` | Live parity check progress |
| `ups_status` | Live UPS status |
| `notifications_overview` | Live notification counts |
| `owner` | Live owner info |
| `server_status` | Live server status |
| `log_tail` | Live log tail stream (requires `path`) |
| `notification_feed` | Live notification feed |
---
### `diagnose_subscriptions` — Subscription Diagnostics
Inspect WebSocket subscription connection states, errors, and URLs. No parameters required.
---
### `test_subscription_query` — Subscription Query Tester
Test a specific GraphQL subscription query against the live Unraid API. Uses an allowlisted set of safe fields only.
---
## Destructive Actions
All require `confirm=True`. Without it, the action is blocked.
| Domain | Subaction |
|--------|-----------|
| `array` | `stop_array`, `remove_disk`, `clear_disk_stats` |
| `vm` | `force_stop`, `reset` |
| `notification` | `delete`, `delete_archived` |
| `rclone` | `delete_remote` |
| `key` | `delete` |
| `disk` | `flash_backup` |
| `setting` | `configure_ups` |
| `plugin` | `remove` |
---
## Support ## Support
- **Issues:** https://github.com/jmagar/unraid-mcp/issues - **Issues:** https://github.com/jmagar/unraid-mcp/issues
- **Repository:** https://github.com/jmagar/unraid-mcp - **Repository:** https://github.com/jmagar/unraid-mcp
- **Skill docs:** `skills/unraid/SKILL.md`
- **API reference:** `skills/unraid/references/`

View File

@@ -5,17 +5,18 @@
"email": "jmagar@users.noreply.github.com" "email": "jmagar@users.noreply.github.com"
}, },
"metadata": { "metadata": {
"description": "Comprehensive Unraid server management and monitoring via a single consolidated MCP tool (~108 actions across 15 domains)", "description": "Unraid server management via 3 MCP tools: `unraid` (107 subactions across 15 domains), `diagnose_subscriptions`, and `test_subscription_query`",
"version": "1.1.2", "version": "1.1.4",
"homepage": "https://github.com/jmagar/unraid-mcp", "homepage": "https://github.com/jmagar/unraid-mcp",
"repository": "https://github.com/jmagar/unraid-mcp" "repository": "https://github.com/jmagar/unraid-mcp"
}, },
"plugins": [ "plugins": [
{ {
"name": "unraid", "name": "unraid",
"displayName": "unRAID",
"source": "./", "source": "./",
"description": "Query, monitor, and manage Unraid servers via GraphQL API — single `unraid` tool with action+subaction routing for array, disk, docker, VM, notifications, live metrics, and more", "description": "Query, monitor, and manage Unraid servers via GraphQL API.\n\nTools: `unraid` (primary), `diagnose_subscriptions`, `test_subscription_query`\n\nActions + subactions:\n• system: overview, array, network, registration, variables, metrics, services, display, config, online, owner, settings, server, servers, flash, ups_devices, ups_device, ups_config\n• health: check, test_connection, diagnose, setup\n• array: parity_status, parity_history, parity_start, parity_pause, parity_resume, parity_cancel, start_array, stop_array*, add_disk, remove_disk*, mount_disk, unmount_disk, clear_disk_stats*\n• disk: shares, disks, disk_details, log_files, logs, flash_backup*\n• docker: list, details, start, stop, restart, networks, network_details\n• vm: list, details, start, stop, pause, resume, force_stop*, reboot, reset*\n• notification: overview, list, create, archive, mark_unread, recalculate, archive_all, archive_many, unarchive_many, unarchive_all, delete*, delete_archived*\n• key: list, get, create, update, delete*, add_role, remove_role\n• plugin: list, add, remove*\n• rclone: list_remotes, config_form, create_remote, delete_remote*\n• setting: update, configure_ups*\n• customization: theme, public_theme, is_initial_setup, sso_enabled, set_theme\n• oidc: providers, provider, configuration, public_providers, validate_session\n• user: me\n• live: cpu, memory, cpu_telemetry, array_state, parity_progress, ups_status, notifications_overview, notification_feed, log_tail, owner, server_status\n\n* = destructive, requires confirm=True",
"version": "1.1.2", "version": "1.1.4",
"tags": ["unraid", "monitoring", "homelab", "graphql", "docker", "virtualization"], "tags": ["unraid", "monitoring", "homelab", "graphql", "docker", "virtualization"],
"category": "infrastructure" "category": "infrastructure"
} }

View File

@@ -1,7 +1,8 @@
{ {
"name": "unraid", "name": "unraid",
"description": "Query, monitor, and manage Unraid servers via GraphQL API - array status, disk health, containers, VMs, system monitoring", "displayName": "unRAID",
"version": "1.1.3", "description": "Query, monitor, and manage Unraid servers via GraphQL API.\n\nTools: `unraid` (primary), `diagnose_subscriptions`, `test_subscription_query`\n\nActions + subactions:\n• system: overview, array, network, registration, variables, metrics, services, display, config, online, owner, settings, server, servers, flash, ups_devices, ups_device, ups_config\n• health: check, test_connection, diagnose, setup\n• array: parity_status, parity_history, parity_start, parity_pause, parity_resume, parity_cancel, start_array, stop_array*, add_disk, remove_disk*, mount_disk, unmount_disk, clear_disk_stats*\n• disk: shares, disks, disk_details, log_files, logs, flash_backup*\n• docker: list, details, start, stop, restart, networks, network_details\n• vm: list, details, start, stop, pause, resume, force_stop*, reboot, reset*\n• notification: overview, list, create, archive, mark_unread, recalculate, archive_all, archive_many, unarchive_many, unarchive_all, delete*, delete_archived*\n• key: list, get, create, update, delete*, add_role, remove_role\n• plugin: list, add, remove*\n• rclone: list_remotes, config_form, create_remote, delete_remote*\n• setting: update, configure_ups*\n• customization: theme, public_theme, is_initial_setup, sso_enabled, set_theme\n• oidc: providers, provider, configuration, public_providers, validate_session\n• user: me\n• live: cpu, memory, cpu_telemetry, array_state, parity_progress, ups_status, notifications_overview, notification_feed, log_tail, owner, server_status\n\n* = destructive, requires confirm=True",
"version": "1.1.5",
"author": { "author": {
"name": "jmagar", "name": "jmagar",
"email": "jmagar@users.noreply.github.com" "email": "jmagar@users.noreply.github.com"

8
.gitignore vendored
View File

@@ -72,3 +72,11 @@ client_secret_*.apps.googleusercontent.com.json
web-ui/frontend/node_modules web-ui/frontend/node_modules
web-ui/backend/.venv-backend/ web-ui/backend/.venv-backend/
.pnpm-store/ .pnpm-store/
# Beads / Dolt files (added by bd init)
.dolt/
*.db
.beads-credential-key
# Lavra
.lavra/memory/session-state.md

View File

@@ -0,0 +1,89 @@
# Codebase Profile
Generated by /project-setup on 2026-03-27
## Stack & Integrations
**Language & Runtime**
- Python 3.12+ (min requirement), supports 3.13
- Build system: Hatchling 1.25.0+, package manager: uv
**Core Frameworks**
- FastMCP 3.0.0+: MCP server framework
- FastAPI 0.115.0+, Uvicorn 0.35.0+: ASGI layer
- Pydantic: validation/serialization
**API & Communication**
- httpx 0.28.1+: async HTTP client for GraphQL queries
- websockets 15.0.1+: WebSocket client for real-time subscriptions
- graphql-core 3.2.0+: GraphQL query validation (dev dep)
**Configuration**
- python-dotenv 1.1.1+: env var management
- rich 14.1.0+: terminal output/logging
**Testing**
- pytest 8.4.2+, pytest-asyncio 1.2.0+, pytest-cov 7.0.0+
- respx 0.22.0+: httpx request mocking
- hypothesis 6.151.9+: property-based testing
**Quality**
- ruff 0.12.8+: lint/format; ty 0.0.15+: type checking
**External Dependencies**
- Unraid GraphQL API (primary backend via httpx)
- WebSocket subscriptions to Unraid server (persistent connections)
- Supports custom CA certs (UNRAID_VERIFY_SSL)
**Entry Points**
- CLI: `unraid-mcp-server` / `unraid` bin scripts
- 1 primary MCP tool: `unraid` (15 domains, ~108 subactions)
- 2 diagnostic tools: `diagnose_subscriptions`, `test_subscription_query`
- 10 live snapshot MCP resources under `unraid://` namespace
## Architecture & Structure
```
unraid_mcp/
├── core/ # GraphQL client, exceptions, types, guards
├── config/ # Settings, logging, env validation
├── tools/ # Consolidated unraid tool (15 action domains)
├── subscriptions/ # WebSocket manager, resources, diagnostics
├── main.py # Entry point with shutdown cleanup
└── server.py # FastMCP init + 5-layer middleware chain
```
**server.py**: FastMCP init with middleware: logging → error_handling → rate_limiting → response_limiting → caching. Registers all tools/resources at import.
**tools/unraid.py**: Single consolidated tool (~1900 lines). 15 actions dispatch to domain handlers. Destructive actions require `confirm=True`.
**core/client.py**: GraphQL HTTP client (httpx-based) with sensitive key redaction, request/response logging, timeout management, credentials elicitation.
**config/settings.py**: Env var parsing for API URL, credentials, host/port, SSL, timeouts, log level, transport.
**subscriptions/manager.py**: Singleton SubscriptionManager for WebSocket lifecycle and real-time streaming.
**Data Flow**: `unraid(action, subaction)` → domain handler → GraphQL query → httpx → Unraid API → response
**Patterns**:
- Consolidated single-tool MCP (action+subaction multiplexing)
- Singleton SubscriptionManager for WebSocket lifecycle
- Middleware chain (logging wraps all; caching disabled for mutations)
- Elicitation flow for first-run credential setup
## Conventions & Testing
**Test Framework**: pytest with asyncio auto mode; `make_tool_fn` helper in conftest for tool extraction from FastMCP.
**Test Layout**:
- Root: domain unit tests (test_array.py, test_docker.py, etc.)
- tests/safety/: destructive action guard audits
- tests/schema/: GraphQL query validation
- tests/http_layer/: respx-based HTTP mocking
- tests/contract/: response structure contracts
- tests/property/: hypothesis property-based tests
- tests/integration/: WebSocket subscription lifecycle (slow, mock WS)
**Key Patching Rule**: Patch at `unraid_mcp.tools.unraid.make_graphql_request` (tool module level), NOT core module.
**Naming**: `Test{Feature}` classes, async `test_*` methods, `_DOMAIN_QUERIES` dicts, `register_{domain}_tool()` functions.
**CI**: uv-based: lint (ruff) → typecheck (ty) → test (pytest) → version-sync → audit. Coverage 80% with branch coverage. Version sync enforces pyproject.toml ↔ .claude-plugin/plugin.json consistency.
**Ruff config**: line length 100, ignores D1xx/D2xx/D7xx (docstring), S101 (assert in tests).

View File

@@ -0,0 +1,16 @@
---
stack: python
review_agents:
- kieran-python-reviewer
- code-simplicity-reviewer
- security-sentinel
- performance-oracle
plan_review_agents:
- kieran-python-reviewer
- code-simplicity-reviewer
disabled_agents: []
---
<reviewer_context_note>
MCP server for Unraid GraphQL API, built with FastMCP. Single consolidated `unraid` tool with action/subaction routing (~108 subactions across 15 domains). Python 3.12+, uv, ruff, ty (Astral type checker), pytest. Async throughout (httpx, asyncio). No web framework — stdio transport by default, streamable-http in Docker. Tests: unit (mock at tool module level), schema validation, HTTP layer (respx), safety (destructive action guards), integration (WebSocket subscriptions). Destructive actions require confirm=True gating.
</reviewer_context_note>

View File

@@ -2,6 +2,23 @@
All notable changes to this project are documented here. All notable changes to this project are documented here.
## [1.1.5] - 2026-03-27
### Added
- **Beads issue tracking**: `bd init` — Dolt-backed issue tracker with prefix `unraid-mcp-<hash>`, hooks, and AGENTS.md integration
- **Lavra project config**: `.lavra/config/project-setup.md` — stack `python`, review agents (kieran-python-reviewer, code-simplicity-reviewer, security-sentinel, performance-oracle)
- **Codebase profile**: `.lavra/config/codebase-profile.md` — auto-generated stack/architecture/conventions reference for planning and review commands
### Changed
- **`.gitignore`**: Added lavra session-state exclusion (`.lavra/memory/session-state.md`) and beads-related entries
- **`CLAUDE.md`**: Added beads workflow integration block with mandatory `bd` usage rules and session completion protocol
## [1.1.4] - 2026-03-25
### Changed
- **Plugin branding**: `displayName` set to `unRAID` in `plugin.json` and `marketplace.json`
- **Plugin description**: Expanded to list all 3 tools and all 15 action domains with full subaction inventory (107 subactions, destructive actions marked with `*`)
## [1.1.3] - 2026-03-24 ## [1.1.3] - 2026-03-24
### Fixed ### Fixed

View File

@@ -228,3 +228,50 @@ All runtimes (plugin, direct `uv run`) load credentials from `~/.unraid-mcp/.env
```bash ```bash
ln -sf CLAUDE.md AGENTS.md && ln -sf CLAUDE.md GEMINI.md ln -sf CLAUDE.md AGENTS.md && ln -sf CLAUDE.md GEMINI.md
``` ```
<!-- BEGIN BEADS INTEGRATION v:1 profile:minimal hash:ca08a54f -->
## Beads Issue Tracker
This project uses **bd (beads)** for issue tracking. Run `bd prime` to see full workflow context and commands.
### Quick Reference
```bash
bd ready # Find available work
bd show <id> # View issue details
bd update <id> --claim # Claim work
bd close <id> # Complete work
```
### Rules
- Use `bd` for ALL task tracking — do NOT use TodoWrite, TaskCreate, or markdown TODO lists
- Run `bd prime` for detailed command reference and session close protocol
- Use `bd remember` for persistent knowledge — do NOT use MEMORY.md files
## Session Completion
**When ending a work session**, you MUST complete ALL steps below. Work is NOT complete until `git push` succeeds.
**MANDATORY WORKFLOW:**
1. **File issues for remaining work** - Create issues for anything that needs follow-up
2. **Run quality gates** (if code changed) - Tests, linters, builds
3. **Update issue status** - Close finished work, update in-progress items
4. **PUSH TO REMOTE** - This is MANDATORY:
```bash
git pull --rebase
bd dolt push
git push
git status # MUST show "up to date with origin"
```
5. **Clean up** - Clear stashes, prune remote branches
6. **Verify** - All changes committed AND pushed
7. **Hand off** - Provide context for next session
**CRITICAL RULES:**
- Work is NOT complete until `git push` succeeds
- NEVER stop before pushing - that leaves work stranded locally
- NEVER say "ready to push when you are" - YOU must push
- If push fails, resolve and retry until it succeeds
<!-- END BEADS INTEGRATION -->

View File

@@ -10,7 +10,7 @@ build-backend = "hatchling.build"
# ============================================================================ # ============================================================================
[project] [project]
name = "unraid-mcp" name = "unraid-mcp"
version = "1.1.3" version = "1.1.5"
description = "MCP Server for Unraid API - provides tools to interact with an Unraid server's GraphQL API" description = "MCP Server for Unraid API - provides tools to interact with an Unraid server's GraphQL API"
readme = "README.md" readme = "README.md"
license = {file = "LICENSE"} license = {file = "LICENSE"}

2
uv.lock generated
View File

@@ -1572,7 +1572,7 @@ wheels = [
[[package]] [[package]]
name = "unraid-mcp" name = "unraid-mcp"
version = "1.1.2" version = "1.1.4"
source = { editable = "." } source = { editable = "." }
dependencies = [ dependencies = [
{ name = "fastapi" }, { name = "fastapi" },