Resolves review threads:
- PRRT_kwDOO6Hdxs5vNroH (Thread 36): tests now verify generic ToolError message
instead of raw exception text (security: no sensitive data in user-facing errors)
- PRRT_kwDOO6Hdxs5vNuYg (Thread 14): format_kb KB branch now uses :.2f like all
other branches (consistency fix)
- I001/F841/PERF401: fix ruff violations in http_layer, integration, safety tests
Changes:
- tests/test_array.py: match "Failed to execute array/parity_status" (not raw error)
- tests/test_keys.py: match "Failed to execute keys/list" (not raw error)
- tests/test_notifications.py: match "Failed to execute notifications/overview" (not raw error)
- tests/test_storage.py: update format_kb assertion to "512.00 KB" (:.2f format)
- tests/http_layer/test_request_construction.py: remove unused result var (F841)
+ fix import sort (I001)
- tests/safety/test_destructive_guards.py: use list.extend (PERF401) + fix import sort
- unraid_mcp/core/utils.py: format_kb returns f"{k:.2f} KB" for sub-MB values
Co-authored-by: @coderabbitai
Co-authored-by: @cubic-dev-ai
Co-authored-by: @copilot-pull-request-reviewer
Move MCP server configuration from standalone .mcp.json to inline
definition in plugin.json. This consolidates all plugin metadata
in a single location.
- Add type: stdio and env fields to inline config
- Remove redundant .mcp.json file
- Maintains same functionality with cleaner structure
Update .mcp.json to use environment variable
for the --directory argument, ensuring the MCP server works correctly
regardless of where the plugin is installed.
This follows Claude Code plugin best practices for MCP server bundling.
Add .mcp.json to configure the Unraid MCP server as a stdio-based MCP
server for Claude Code plugin integration. This allows Claude Code to
automatically start and connect to the server when the plugin is loaded.
- Type: stdio (standard input/output communication)
- Command: uv run unraid-mcp-server
- Forces stdio transport mode via UNRAID_MCP_TRANSPORT env var
Change source from absolute GitHub URL to relative path "./"
This follows Claude Code marketplace convention where source paths
are relative to the cloned repository root, not external URLs.
Matches pattern from working examples like claude-homelab marketplace.
- Fix marketplace.json: change source from relative path to GitHub URL
(was "skills/unraid", now "https://github.com/jmagar/unraid-mcp")
This resolves the "Invalid input" schema validation error when adding
the marketplace to Claude Code
- Refactor subscriptions autostart to use anyio.Path for async file checks
(replaces blocking pathlib.Path.exists() with async anyio.Path.exists())
- Update dependencies: anyio 4.11.0→4.12.1, attrs 25.3.0→25.4.0
- Rename marketplace from "unraid-mcp" to "jmagar-unraid-mcp" to match expected directory structure
- Wrap description, version, homepage, and repository in metadata object per standard format
- Fixes "Marketplace file not found" error when adding marketplace to Claude Code
Resolves marketplace installation issues by aligning with format used by other Claude Code marketplaces.
Resolves review thread PRRT_kwDOO6Hdxs5uu7z7
- Removed redundant User-Agent header from per-request headers in make_graphql_request()
- User-Agent is already set as default header on the shared HTTP client
- httpx merges per-request headers with client defaults, so client-level default is sufficient
- Fix broken ToC anchors in competitive-analysis.md (MD051)
- Add blank lines before code blocks in api-reference.md (MD031)
- Add language identifiers to directory tree code blocks in MARKETPLACE.md and skills/unraid/README.md (MD040)
- Fix size unit guidance conflict: clarify disk sizes are KB, memory is bytes
- Update stale "90 actions" references to "76 actions" across research docs
- Fix coverage table terminology and clarify 22% coverage calculation
- Recommend PyPI Trusted Publishing (OIDC) over API token secrets in PUBLISHING.md
- Update action count in .claude-plugin/README.md
Resolves review threads: PRRT_kwDOO6Hdxs5uvO2m, PRRT_kwDOO6Hdxs5uvO2o,
PRRT_kwDOO6Hdxs5uvO2r, PRRT_kwDOO6Hdxs5uvOcl, PRRT_kwDOO6Hdxs5uvOcr,
PRRT_kwDOO6Hdxs5uvKrq, PRRT_kwDOO6Hdxs5uvO2u, PRRT_kwDOO6Hdxs5uvO2w,
PRRT_kwDOO6Hdxs5uvO2z, PRRT_kwDOO6Hdxs5uu7zl
- Remove slashes from LOG_NAME regex to block path traversal (e.g.
../../etc/passwd). Only alphanumeric, dots, hyphens, underscores allowed.
- Cap LINES to 1-10000 range to prevent resource exhaustion.
- Add query script existence check before execution.
- Add query failure, empty response, and invalid JSON guards.
Resolves review thread PRRT_kwDOO6Hdxs5uvKrj
- Remove set -e from validate-marketplace.sh to prevent early exit on
check failures, allowing the summary to always be displayed (PRRT_kwDOO6Hdxs5uvKrc)
- Fix marketplace.json source path to point to skills/unraid instead of
./ for correct plugin directory resolution (PRRT_kwDOO6Hdxs5uvKrg)
- Fix misleading trap registration comment in unraid-api-crawl.md and
add auth note to Apollo Studio URL (PRRT_kwDOO6Hdxs5uvO2t)
- Extract duplicated cleanup-with-error-handling in main.py into
_run_shutdown_cleanup() helper (PRRT_kwDOO6Hdxs5uvO3A)
- Add input validation to read-logs.sh to prevent GraphQL injection
via LOG_NAME and LINES parameters (PRRT_kwDOO6Hdxs5uvKrj)
- Rename test_start_http_401_unauthorized to test_list_http_401_unauthorized
to match the actual action="list" being tested (threads #19, #23)
- Use consistent PrefixedID format ("a"*64+":local") in test_start_container
instead of "abc123def456"*4 concatenation (thread #37)
- Refactor container_actions_require_id to use @pytest.mark.parametrize
so each action runs independently (thread #18)
- Fix docstring claiming ToolError for test that asserts success in
test_stop_mutation_returns_null (thread #26)
- Fix inaccurate comment about `in` operator checking truthiness;
it checks key existence (thread #25)
- Add edge case tests for temperature=0, temperature=null, and
logFile=null in test_storage.py (thread #31)
Resolves review threads: PRRT_kwDOO6Hdxs5uvO2-, PRRT_kwDOO6Hdxs5uvOcf,
PRRT_kwDOO6Hdxs5uu7zx, PRRT_kwDOO6Hdxs5uvO28, PRRT_kwDOO6Hdxs5uvOcp,
PRRT_kwDOO6Hdxs5uvOcn, PRRT_kwDOO6Hdxs5uvKr3
- Move plugin.json from skills/unraid/.claude-plugin/ to .claude-plugin/
- Update validation script to use correct plugin manifest path
- Add plugin structure section to root README.md
- Add installation instructions to skills/unraid/README.md
- Aligns with Claude Code's expectation for source: './' in marketplace.json
- Change Subprotocol import from deprecated websockets.legacy.protocol
to websockets.typing (canonical location in websockets 13.x)
- Fix SSL context handling in diagnostics.py to properly build
ssl.SSLContext objects, matching the pattern in manager.py
(previously passed UNRAID_VERIFY_SSL directly which breaks
when it's a CA bundle path string)
- Move _ALLOWED_LOG_PREFIXES to module level (N806: constant naming)
- Use f-string conversion flag {e!s} instead of {str(e)} (RUF010)
- Fix import block sorting in both files (I001)
**Project Configuration:**
- Enhance pyproject.toml with comprehensive metadata, keywords, and classifiers
- Add LICENSE file (MIT) for proper open-source distribution
- Add PUBLISHING.md with comprehensive publishing guidelines
- Update .gitignore to exclude tool artifacts (.cache, .pytest_cache, .ruff_cache, .ty_cache)
- Ignore documentation working directories (.docs, .full-review, docs/plans, docs/sessions)
**Documentation:**
- Add extensive Unraid API research documentation
- API source code analysis and resolver mapping
- Competitive analysis and feature gap assessment
- Release notes analysis (7.0.0, 7.1.0, 7.2.0)
- Connect platform overview and remote access documentation
- Document known API patterns, limitations, and edge cases
**Testing & Code Quality:**
- Expand test coverage across all tool modules
- Add destructive action confirmation tests
- Improve test assertions and error case validation
- Refine type annotations for better static analysis
**Tool Improvements:**
- Enhance error handling consistency across all tools
- Improve type safety with explicit type annotations
- Refine GraphQL query construction patterns
- Better handling of optional parameters and edge cases
This commit prepares the project for v0.2.0 release with improved
metadata, comprehensive documentation, and enhanced code quality.
Co-authored-by: Claude <noreply@anthropic.com>
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.
- Update dev.sh to use /tmp for LOG_DIR instead of PROJECT_DIR/logs
- Update settings.py to use /tmp for LOGS_DIR instead of PROJECT_ROOT/logs
- This change moves both pid files and log files to the temporary directory
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Remove env_file directive from docker-compose.yml to eliminate .env file dependency
- Add explicit environment variable declarations with default values using ${VAR:-default} syntax
- Update port mapping to use UNRAID_MCP_PORT environment variable for both host and container
- Include all 11 environment variables used by the application with proper defaults
- Update README.md Docker deployment instructions to use export commands instead of .env files
- Update manual Docker run command to use -e flags instead of --env-file
This makes Docker deployment self-contained and follows container best practices.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Create OverwriteFileHandler class that caps log files at 10MB and overwrites instead of rotating
- Remove RotatingFileHandler dependency and backup file creation
- Add reset marker logging when file limit is reached for troubleshooting
- Update all logger configurations (main, FastMCP, and root loggers)
- Increase file size limit from 5MB to 10MB as requested
- Maintain existing Rich console formatting and error handling
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Added KFC (Kent Feature Creator) spec workflow agents for requirements, design, tasks, testing, implementation and evaluation
- Added Claude Code settings configuration for agent workflows
- Added GraphQL introspection query and schema files for Unraid API exploration
- Updated development script with additional debugging and schema inspection capabilities
- Enhanced logging configuration with structured formatting
- Updated pyproject.toml dependencies and uv.lock
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Remove array_status, system_info, notifications_overview, and parity_status resources
- Keep only logs_stream resource (unraid://logs/stream) which is working properly
- Update README.md with current resource documentation and modern docker compose syntax
- Fix import path issues that were causing subscription errors
- Update environment configuration examples
- Clean up subscription manager to only include working log streaming
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Replace pip/requirements.txt with uv and pyproject.toml
- Restructure as single-file MCP server using FastMCP
- Add comprehensive Unraid management tools (containers, VMs, storage, logs)
- Implement multiple transport support (streamable-http, SSE, stdio)
- Add robust error handling and timeout management
- Include project documentation and API feature tracking
- Remove outdated cline documentation structure
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>