Resolves review threads: - PRRT_kwDOO6Hdxs50fewG (setup.py): non-eliciting clients now return True from elicit_reset_confirmation so they can reconfigure without being blocked - PRRT_kwDOO6Hdxs50fewM (test-tools.sh): add notification/recalculate smoke test - PRRT_kwDOO6Hdxs50fewP (test-tools.sh): add system/array smoke test - PRRT_kwDOO6Hdxs50fewT (resources.py): surface manager error state instead of reporting 'connecting' for permanently failed subscriptions - PRRT_kwDOO6Hdxs50feAj (resources.py): use is not None check for empty cached dicts - PRRT_kwDOO6Hdxs50fewY (integration tests): remove duplicate snapshot-registration tests already covered in test_resources.py - PRRT_kwDOO6Hdxs50fewe (test_resources.py): replace brittle import-detail test with behavior tests for connecting/error states - PRRT_kwDOO6Hdxs50fewh (test_customization.py): strengthen public_theme assertion - PRRT_kwDOO6Hdxs50fewk (test_customization.py): strengthen theme assertion - PRRT_kwDOO6Hdxs50fewo (__init__.py): correct subaction count ~88 -> ~107 - PRRT_kwDOO6Hdxs50fewx (test_oidc.py): assert providers list value directly - PRRT_kwDOO6Hdxs50fewz (unraid.py): remove unreachable raise after vm handler - PRRT_kwDOO6Hdxs50few2 (unraid.py): remove unreachable raise after docker handler - PRRT_kwDOO6Hdxs50fev8 (CLAUDE.md): replace legacy 15-tool table with unified unraid action/subaction table - PRRT_kwDOO6Hdxs50fev_ (test_oidc.py): assert providers + defaultAllowedOrigins - PRRT_kwDOO6Hdxs50feAz (CLAUDE.md): update tool categories to unified API shape - PRRT_kwDOO6Hdxs50feBE (CLAUDE.md/setup.py): update unraid_health refs to unraid(action=health, subaction=setup)
mcporter Integration Tests
Live integration smoke-tests for the unraid-mcp server, exercising real API calls via mcporter.
Two Scripts, Two Transports
test-tools.sh |
test-actions.sh |
|
|---|---|---|
| Transport | stdio | HTTP |
| Server required | No — launched ad-hoc per call | Yes — must be running at $MCP_URL |
| Flags | --timeout-ms N, --parallel, --verbose |
positional [MCP_URL] |
| Coverage | 10 tools (read-only actions only) | 11 tools (all non-destructive actions) |
| Use case | CI / offline local check | Live server smoke-test |
test-tools.sh — stdio, no running server needed
./tests/mcporter/test-tools.sh # sequential, 25s timeout
./tests/mcporter/test-tools.sh --parallel # parallel suites
./tests/mcporter/test-tools.sh --timeout-ms 10000 # tighter timeout
./tests/mcporter/test-tools.sh --verbose # print raw responses
Launches uv run unraid-mcp-server in stdio mode for each tool call. Requires mcporter, uv, and python3 in PATH. Good for CI pipelines — no persistent server process needed.
test-actions.sh — HTTP, requires a live server
./tests/mcporter/test-actions.sh # default: http://localhost:6970/mcp
./tests/mcporter/test-actions.sh http://10.1.0.2:6970/mcp # explicit URL
UNRAID_MCP_URL=http://10.1.0.2:6970/mcp ./tests/mcporter/test-actions.sh
Connects to an already-running streamable-http server. Covers all read-only actions across 10 tools (unraid_settings is all-mutations and skipped; all destructive mutations are explicitly skipped).
What test-actions.sh Tests
Phase 1 — Param-free reads
All actions requiring no arguments beyond action itself.
| Tool | Actions tested |
|---|---|
unraid_info |
overview, array, network, registration, connect, variables, metrics, services, display, config, online, owner, settings, server, servers, flash, ups_devices, ups_device, ups_config |
unraid_array |
parity_status |
unraid_storage |
disks, shares, unassigned, log_files |
unraid_docker |
list, networks, port_conflicts, check_updates, sync_templates, refresh_digests |
unraid_vm |
list |
unraid_notifications |
overview, list, warnings, recalculate |
unraid_rclone |
list_remotes, config_form |
unraid_users |
me |
unraid_keys |
list |
unraid_health |
check, test_connection, diagnose |
unraid_settings |
(all 9 actions skipped — mutations only) |
Phase 2 — ID-discovered reads
IDs are extracted from Phase 1 responses and used for actions requiring a specific resource. Each is skipped if Phase 1 returned no matching resources.
| Action | Source of ID |
|---|---|
docker: details |
first container from docker: list |
docker: logs |
first container from docker: list |
docker: network_details |
first network from docker: networks |
storage: disk_details |
first disk from storage: disks |
storage: logs |
first path from storage: log_files |
vm: details |
first VM from vm: list |
keys: get |
first key from keys: list |
Skipped actions (and why)
| Label | Meaning |
|---|---|
destructive (confirm=True required) |
Permanently modifies or deletes data |
mutation — state-changing |
Modifies live system state (container/VM lifecycle, settings) |
mutation — creates … |
Creates a new resource |
Full skip list:
unraid_info:update_server,update_sshunraid_array:parity_start,parity_pause,parity_resume,parity_cancelunraid_storage:flash_backupunraid_docker:start,stop,restart,pause,unpause,update,remove,update_all,create_folder,set_folder_children,delete_entries,move_to_folder,move_to_position,rename_folder,create_folder_with_items,update_view_prefs,reset_template_mappingsunraid_vm:start,stop,pause,resume,reboot,force_stop,resetunraid_notifications:create,create_unique,archive,unread,archive_all,archive_many,unarchive_many,unarchive_all,delete,delete_archivedunraid_rclone:create_remote,delete_remoteunraid_keys:create,update,deleteunraid_settings: all 9 actions
Output format
<action label> PASS
<action label> FAIL
<first 3 lines of error detail>
<action label> SKIP (reason)
Results: 42 passed 0 failed 37 skipped (79 total)
Exit code 0 when all executed tests pass, 1 if any fail.
Destructive Actions
Neither script executes destructive actions. They are explicitly skip_test-ed with reason "destructive (confirm=True required)".
All destructive actions require confirm=True at the call site. There is no environment variable gate — confirm is the sole guard.
Safe Testing Strategy
| Strategy | When to use |
|---|---|
| Create → destroy | Action has a create counterpart (keys, notifications, rclone remotes, docker folders) |
| No-op apply | Action mutates config but can be re-applied with current values unchanged (update_ssh) |
| Dedicated test remote | Action requires a remote target (flash_backup) |
| Test VM | Action requires a live VM (force_stop, reset) |
| Mock/safety audit only | Global blast radius, no safe isolation (update_all, reset_template_mappings, setup_remote_access, configure_ups) |
| Secondary server only | Run on shart (10.1.0.3), never tootie (10.1.0.2) |
For exact per-action mcporter commands, see docs/DESTRUCTIVE_ACTIONS.md.
Prerequisites
# mcporter CLI
npm install -g mcporter
# uv (for test-tools.sh stdio mode)
curl -LsSf https://astral.sh/uv/install.sh | sh
# python3 — used for inline JSON extraction
python3 --version # 3.12+
# Running server (for test-actions.sh only)
docker compose up -d
# or
uv run unraid-mcp-server
Cleanup
test-actions.sh connects to an existing server and leaves it running; it creates no temporary files. test-tools.sh spawns stdio server subprocesses per call — they exit when mcporter finishes each invocation — and may write a timestamped log file under ${TMPDIR:-/tmp}. Neither script leaves background processes.