Jacob Magar
72ccf9b074
chore: add settings slash command and bump to 0.4.8
...
- Add commands/settings.md slash command for unraid_settings tool
- Sync uv.lock after version bump
Co-authored-by: Claude <claude@anthropic.com >
2026-03-14 16:40:04 -04:00
Jacob Magar
5740f4848a
chore: bump version to 0.4.7
2026-03-14 14:49:13 -04:00
Jacob Magar
4ce3edd423
docs: update credential setup to reflect ~/.unraid-mcp/.env flow
2026-03-14 14:48:06 -04:00
Jacob Magar
2c0f4a1730
feat(creds): add optional env_file from ~/.unraid-mcp/.env to docker-compose
2026-03-14 14:46:10 -04:00
Jacob Magar
a3754e37c3
feat(creds): setup declined message includes manual path and variable names
2026-03-14 14:45:35 -04:00
Jacob Magar
c4f1b2eb00
test(creds): add replacement test for credentials propagation through tool_error_handler
2026-03-14 14:21:21 -04:00
Jacob Magar
c80ab0ca6b
refactor(creds): remove per-tool elicitation from unraid_info
2026-03-14 14:20:20 -04:00
Jacob Magar
08afdcc50e
refactor(creds): remove per-tool elicitation from unraid_settings
2026-03-14 14:19:42 -04:00
Jacob Magar
ba7b8dfaa6
refactor(creds): remove per-tool elicitation from unraid_keys
2026-03-14 14:18:20 -04:00
Jacob Magar
23e70e46d0
refactor(creds): remove per-tool elicitation from unraid_users
2026-03-14 14:17:14 -04:00
Jacob Magar
fe66e8742c
refactor(creds): remove per-tool elicitation from unraid_rclone
2026-03-14 14:16:34 -04:00
Jacob Magar
77f3d897a3
refactor(creds): remove per-tool elicitation from unraid_notifications
2026-03-14 14:16:07 -04:00
Jacob Magar
8c67145bcc
refactor(creds): remove per-tool elicitation from unraid_vm
2026-03-14 14:14:22 -04:00
Jacob Magar
9fc85ea48c
refactor(creds): remove per-tool elicitation from unraid_storage
2026-03-14 14:13:52 -04:00
Jacob Magar
d99855973a
refactor(creds): remove per-tool elicitation from unraid_docker
2026-03-14 14:13:14 -04:00
Jacob Magar
9435a8c534
refactor(creds): remove per-tool elicitation from unraid_array
2026-03-14 14:09:14 -04:00
Jacob Magar
81f1fe174d
feat(creds): tool_error_handler converts CredentialsNotConfiguredError to ToolError with path
...
Converts the CredentialsNotConfiguredError sentinel to a user-facing ToolError
in tool_error_handler, including the exact CREDENTIALS_ENV_PATH so users know
where to create the .env file. Removes the now-invalid per-tool elicitation
test (replaced by 2 new tests for the handler conversion behavior).
2026-03-14 14:05:59 -04:00
Jacob Magar
e930b868e4
feat(creds): write to ~/.unraid-mcp/.env with 700/600 permissions, seed from .env.example
...
- _write_env now creates CREDENTIALS_DIR (mode 700) and writes credentials
to CREDENTIALS_ENV_PATH (mode 600) instead of PROJECT_ROOT/.env
- On first run (no .env yet), seeds file content from .env.example to
preserve comments and structure
- elicit_and_configure catches NotImplementedError from ctx.elicit() so
clients that don't support elicitation return False gracefully instead
of propagating the exception
- Updated test_elicit_and_configure_writes_env_file to patch CREDENTIALS_DIR
and CREDENTIALS_ENV_PATH instead of PROJECT_ROOT
- Added 5 new tests covering dir/file permissions, .env.example seeding,
in-place credential update, and NotImplementedError guard
2026-03-14 14:00:57 -04:00
Jacob Magar
d8ce45c0fc
feat(creds): add CREDENTIALS_DIR and CREDENTIALS_ENV_PATH to settings
...
Introduce a version-agnostic credential directory (~/.unraid-mcp, overridable
via UNRAID_CREDENTIALS_DIR env var) and surface it as CREDENTIALS_DIR and
CREDENTIALS_ENV_PATH module-level constants. Prepend the canonical .env path to
dotenv_paths so all runtimes (plugin, uv, Docker) resolve credentials from the
same stable location without relying on versioned plugin cache paths.
2026-03-14 13:54:14 -04:00
Jacob Magar
14e9dca8bc
chore: bump version to 0.4.6
2026-03-14 04:30:01 -04:00
Jacob Magar
f0a97edbf7
docs: update credential setup docs to reflect elicitation flow
2026-03-14 04:29:35 -04:00
Jacob Magar
85cd173449
fix(elicitation): guard ctx=None in elicit_and_configure, cover all settings/docker/notifications actions
...
- setup.py: elicit_and_configure now accepts Context | None; returns False
immediately when ctx is None instead of crashing with AttributeError
- settings.py: added CredentialsNotConfiguredError try/except guard around
make_graphql_request calls in all 8 previously-unguarded actions
(update_temperature, update_time, configure_ups, update_api, connect_sign_in,
connect_sign_out, setup_remote_access, enable_dynamic_remote_access)
- docker.py: added guards to all 20 previously-unguarded make_graphql_request
calls (details, logs, networks, network_details, port_conflicts, check_updates,
restart, update_all, all 11 organizer mutations, and single-container fallback)
- notifications.py: added guards to all 11 previously-unguarded calls
(list, warnings, create, archive/unread, delete, delete_archived, archive_all,
archive_many, create_unique, unarchive_many, unarchive_all, recalculate)
2026-03-14 04:28:34 -04:00
Jacob Magar
e1c80cf1da
feat(elicitation): add ctx + credential elicitation to unraid_settings
2026-03-14 04:19:08 -04:00
Jacob Magar
ba14a8d341
feat(elicitation): add ctx + credential elicitation to unraid_keys
2026-03-14 04:18:06 -04:00
Jacob Magar
cec254b432
feat(elicitation): add ctx + credential elicitation to unraid_users
2026-03-14 04:17:17 -04:00
Jacob Magar
dec80832ea
feat(elicitation): add ctx + credential elicitation to unraid_rclone
2026-03-14 04:16:54 -04:00
Jacob Magar
4b4c8ddf63
feat(elicitation): add ctx + credential elicitation to unraid_notifications
2026-03-14 04:16:08 -04:00
Jacob Magar
dfcaa37614
feat(elicitation): add ctx + credential elicitation to unraid_vm
2026-03-14 04:14:43 -04:00
Jacob Magar
060acab239
feat(elicitation): add ctx + credential elicitation to unraid_storage
2026-03-14 04:14:15 -04:00
Jacob Magar
be186dc2d7
feat(elicitation): add ctx + credential elicitation to unraid_docker
2026-03-14 04:13:34 -04:00
Jacob Magar
13f85bd499
feat(elicitation): add ctx + credential elicitation to unraid_array
2026-03-14 04:11:38 -04:00
Jacob Magar
49264550b1
feat(elicitation): auto-elicit credentials on CredentialsNotConfiguredError in unraid_info
2026-03-14 04:07:51 -04:00
Jacob Magar
9be46750b8
feat(elicitation): add setup action to unraid_health
2026-03-14 04:02:15 -04:00
Jacob Magar
61604b313f
fix(elicitation): pass CredentialsNotConfiguredError through tool_error_handler
2026-03-14 03:58:44 -04:00
Jacob Magar
8a986a84c2
feat(elicitation): raise CredentialsNotConfiguredError in client when creds absent
...
make_graphql_request now reads credentials from the settings module at call
time (via a local import) instead of relying on module-level names captured at
import time. When either credential is missing it raises CredentialsNotConfiguredError
(not ToolError), allowing callers to trigger elicitation rather than surfacing a
generic error to the MCP client.
Updated tests/test_client.py and tests/http_layer/test_request_construction.py
to patch unraid_mcp.config.settings.* instead of the now-removed client-module
attrs, and to expect CredentialsNotConfiguredError on missing credentials.
2026-03-14 03:55:57 -04:00
Jacob Magar
02e61b4290
refactor(elicitation): use PROJECT_ROOT directly (already a Path)
2026-03-14 03:50:45 -04:00
Jacob Magar
e73f791fd3
feat(elicitation): add elicit_and_configure() with .env persistence
2026-03-14 03:49:11 -04:00
Jacob Magar
7458409147
test(elicitation): assert warning is logged when creds missing at startup
2026-03-14 03:47:29 -04:00
Jacob Magar
42bfcc1998
feat(elicitation): degrade gracefully when credentials are missing at startup
2026-03-14 03:45:42 -04:00
Jacob Magar
a7988e1eae
test(elicitation): fix os.environ leak in apply_runtime_config test
2026-03-14 03:44:34 -04:00
Jacob Magar
520d92af57
feat(elicitation): add is_configured() and apply_runtime_config() to settings
2026-03-14 03:43:20 -04:00
Jacob Magar
1952720ef9
test(elicitation): fix test_setup.py style and add ToolError contract test
2026-03-14 03:41:24 -04:00
Jacob Magar
ea839ec09c
feat(elicitation): add CredentialsNotConfiguredError sentinel
2026-03-14 03:39:49 -04:00
Jacob Magar
b734eff902
docs: add version bump reminder to CLAUDE.md
...
Always update both pyproject.toml and .claude-plugin/plugin.json
when bumping versions — missed in 0.4.4→0.4.5 bump.
Co-Authored-By: Claude <noreply@anthropic.com >
2026-03-14 03:11:04 -04:00
Jacob Magar
3f13cf89c8
chore: bump plugin.json version to 0.4.5
...
Co-Authored-By: Claude <noreply@anthropic.com >
2026-03-14 03:09:58 -04:00
Jacob Magar
af3b5818dc
refactor: merge comprehensive code review fixes branch
...
Merges 35 commits from refactor/comprehensive-code-review-fixes:
- Critical/high/medium/low PR review findings addressed
- Test suite reorganized (safety, http_layer, schema, integration)
- Destructive action guard tests added
- Rclone bug fix, diagnostics improvements
- Version bump to 0.4.5
Co-Authored-By: Claude <noreply@anthropic.com >
2026-03-14 03:01:59 -04:00
Jacob Magar
d47101f8f7
chore: bump version to 0.4.5, update lock file
...
Co-Authored-By: Claude <noreply@anthropic.com >
2026-03-14 03:01:21 -04:00
Jacob Magar
d0cc99711a
fix: address remaining PR review threads (docs, test-destructive, rclone test)
...
Resolves review threads:
- PRRT_kwDOO6Hdxs50T0Wp (test-destructive.sh: add key cleanup on failure path)
- PRRT_kwDOO6Hdxs50T0Ws (test-destructive.sh: pick last notification match by title)
- PRRT_kwDOO6Hdxs50T0Wt (README.md: correct test-actions.sh coverage description)
- PRRT_kwDOO6Hdxs50T0Wv (CLAUDE.md: add info.update_ssh to destructive actions list)
- PRRT_kwDOO6Hdxs50T0Wy (http_layer test: inp["config"] -> inp["parameters"])
- PRRT_kwDOO6Hdxs50T0Wz (DESTRUCTIVE_ACTIONS.md: key ID extraction key.id not top-level)
- PRRT_kwDOO6Hdxs50T0W2 (DESTRUCTIVE_ACTIONS.md: delete_archived — add archive step)
- PRRT_kwDOO6Hdxs50T0W3 (DESTRUCTIVE_ACTIONS.md: rclone params provider_type/config_data/name)
- PRRT_kwDOO6Hdxs50T0W4 (DESTRUCTIVE_ACTIONS.md: notification delete list+match pattern)
- PRRT_kwDOO6Hdxs50T0W5 (DESTRUCTIVE_ACTIONS.md: create_folder uses folder_name param)
- PRRT_kwDOO6Hdxs50T0W7 (README.md: cleanup note — test-tools.sh may write tmp log file)
Changes:
- test-destructive.sh keys test: attempt key delete cleanup when delete step fails
- test-destructive.sh notifications test: reverse list to pick most-recent title match
- tests/mcporter/README.md: accurate coverage claim; accurate cleanup section
- CLAUDE.md: info.update_ssh added to destructive actions list
- tests/http_layer/test_request_construction.py: assert parameters not config field
- docs/DESTRUCTIVE_ACTIONS.md: all 5 example code blocks corrected with right
parameter names, correct ID extraction paths, and proper sequencing
Co-authored-by: Claude <noreply@anthropic.com >
2026-03-13 23:29:14 -04:00
Jacob Magar
91bce1dbd5
fix: address PR review threads (test-actions, diagnostics, docker, health, storage, plugin)
...
Resolves review threads:
- PRRT_kwDOO6Hdxs50R8VI (test-actions.sh: remove || echo "000" curl fallback)
- PRRT_kwDOO6Hdxs50R8VJ (test-actions.sh: JSON parse failures → FAIL not silent)
- PRRT_kwDOO6Hdxs50QdKd (diagnostics.py: sanitize raw exception text from ToolError)
- PRRT_kwDOO6Hdxs50QdKs (storage.py: unassigned uses unassignedDevices query)
- PRRT_kwDOO6Hdxs50Mwlk (docker.py: port_conflicts returns flat merged list)
- PRRT_kwDOO6Hdxs50Mwlo (docker.py: logs returns plain string not dict)
- PRRT_kwDOO6Hdxs50Mt5K (docker.py: unraid_docker logs format compatibility)
- PRRT_kwDOO6Hdxs50Mt5L (health.py: or {} null guards throughout)
- PRRT_kwDOO6Hdxs50Mt5r (docker.py: port_conflicts flat list backward compat)
- plugin.json: version synced to 0.4.4 to match pyproject.toml
Changes:
- test-actions.sh: curl exit code captured directly; JSON failures surface as FAIL
- diagnostics.py: 4 ToolError sites log exc_info=True, raise sanitized messages
- storage.py: unassigned action queries unassignedDevices instead of disks
- docker.py: logs action returns newline-joined string; port_conflicts merges
containerPorts + lanPorts into a flat list for backward compatibility
- health.py: all nested dict lookups use `or {}` instead of `.get(k, {})` to
handle explicit GraphQL null values
Co-authored-by: Claude <noreply@anthropic.com >
2026-03-13 23:19:50 -04:00
Jacob Magar
7bb9d93bd5
chore: reorganize test scripts, add destructive action tests, fix rclone bug
...
- Move scripts/test-tools.sh and scripts/test-actions.sh → tests/mcporter/
- Fix PROJECT_DIR path in test-tools.sh (SCRIPT_DIR/.. → SCRIPT_DIR/../..)
- Add tests/mcporter/test-destructive.sh: 2 live + 13 skipped destructive tests
- stdio transport (no running server required)
- notifications:delete (create→list→delete), keys:delete (create→delete→verify)
- 3 new skips: createDockerFolder/updateSshSettings/createRCloneRemote not in API
- Requires --confirm flag; dry-run by default
- Add tests/mcporter/README.md documenting both scripts and coverage
- Rewrite docs/DESTRUCTIVE_ACTIONS.md: merge test guide, all 15 actions with commands
- Delete docs/test-actions.md (merged into tests/mcporter/README.md)
- Fix rclone.py create_remote: send "parameters" not "config" (API field name)
- Update README.md and CLAUDE.md: 11 tools/~104 actions, new script paths
- Add AGENTS.md and GEMINI.md symlinks to CLAUDE.md
- Bump version 0.4.3 → 0.4.4
Co-authored-by: Claude <noreply@anthropic.com >
2026-03-13 22:35:52 -04:00