feat: consolidate 26 tools into 10 tools with 90 actions

Refactor the entire tool layer to use the consolidated action pattern
(action: Literal[...] with QUERIES/MUTATIONS dicts). This reduces LLM
context from ~12k to ~5k tokens while adding ~60 new API capabilities.

New tools: unraid_info (19 actions), unraid_array (12), unraid_notifications (9),
unraid_users (8), unraid_keys (5). Rewritten: unraid_docker (15), unraid_vm (9),
unraid_storage (6), unraid_rclone (4), unraid_health (3).

Includes 129 tests across 10 test files, code review fixes for 16 issues
(severity ordering, PrefixedID regex, sensitive var redaction, etc.).

Removes tools/system.py (replaced by tools/info.py). Version bumped to 0.2.0.
This commit is contained in:
Jacob Magar
2026-02-08 08:49:47 -05:00
parent 67b775a9bc
commit 523b3edc76
33 changed files with 3538 additions and 1583 deletions

View File

@@ -30,10 +30,10 @@ console = Console(stderr=True, force_terminal=True)
class OverwriteFileHandler(logging.FileHandler):
"""Custom file handler that overwrites the log file when it reaches max size."""
def __init__(self, filename, max_bytes=10*1024*1024, mode='a', encoding=None, delay=False):
"""Initialize the handler.
Args:
filename: Path to the log file
max_bytes: Maximum file size in bytes before overwriting (default: 10MB)
@@ -43,7 +43,7 @@ class OverwriteFileHandler(logging.FileHandler):
"""
self.max_bytes = max_bytes
super().__init__(filename, mode, encoding, delay)
def emit(self, record):
"""Emit a record, checking file size and overwriting if needed."""
# Check file size before writing
@@ -56,14 +56,14 @@ class OverwriteFileHandler(logging.FileHandler):
if self.stream:
self.stream.close()
self.stream = None
# Remove the old file and start fresh
if os.path.exists(self.baseFilename):
os.remove(self.baseFilename)
# Reopen with truncate mode
self.stream = self._open()
# Log a marker that the file was reset
reset_record = logging.LogRecord(
name="UnraidMCPServer.Logging",
@@ -75,11 +75,11 @@ class OverwriteFileHandler(logging.FileHandler):
exc_info=None
)
super().emit(reset_record)
except (OSError, IOError):
except OSError:
# If there's an issue checking file size, just continue normally
pass
# Emit the original record
super().emit(record)

View File

@@ -29,6 +29,9 @@ for dotenv_path in dotenv_paths:
load_dotenv(dotenv_path=dotenv_path)
break
# Application Version
VERSION = "0.2.0"
# Core API Configuration
UNRAID_API_URL = os.getenv("UNRAID_API_URL")
UNRAID_API_KEY = os.getenv("UNRAID_API_KEY")