forked from HomeLab/unraid-mcp
feat: harden API safety and expand command docs with full test coverage
This commit is contained in:
240
docs/DESTRUCTIVE_ACTIONS.md
Normal file
240
docs/DESTRUCTIVE_ACTIONS.md
Normal file
@@ -0,0 +1,240 @@
|
||||
# Destructive Actions Inventory
|
||||
|
||||
This file lists all destructive actions across the unraid-mcp tools. Fill in the "Testing Strategy" column to specify how each should be tested in the mcporter integration test suite.
|
||||
|
||||
**Last Updated:** 2026-02-15
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
- **Total Destructive Actions:** 8 (after removing 4 array operations)
|
||||
- **Tools with Destructive Actions:** 6
|
||||
- **Environment Variable Gates:** 6 (one per tool)
|
||||
|
||||
---
|
||||
|
||||
## Destructive Actions by Tool
|
||||
|
||||
### 1. Docker (1 action)
|
||||
|
||||
| Action | Description | Risk Level | Env Var Gate | Testing Strategy |
|
||||
|--------|-------------|------------|--------------|------------------|
|
||||
| `remove` | Permanently delete a Docker container | **HIGH** - Data loss, irreversible | `UNRAID_ALLOW_DOCKER_DESTRUCTIVE` | **TODO: Specify testing approach** |
|
||||
|
||||
**Notes:**
|
||||
- Container must be stopped first
|
||||
- Removes container config and any non-volume data
|
||||
- Cannot be undone
|
||||
|
||||
---
|
||||
|
||||
### 2. Virtual Machines (2 actions)
|
||||
|
||||
| Action | Description | Risk Level | Env Var Gate | Testing Strategy |
|
||||
|--------|-------------|------------|--------------|------------------|
|
||||
| `force_stop` | Forcefully power off a running VM (equivalent to pulling power cord) | **MEDIUM** - Severe but recoverable, risk of data corruption | `UNRAID_ALLOW_VM_DESTRUCTIVE` | **TODO: Specify testing approach** |
|
||||
| `reset` | Hard reset a VM (power cycle without graceful shutdown) | **MEDIUM** - Severe but recoverable, risk of data corruption | `UNRAID_ALLOW_VM_DESTRUCTIVE` | **TODO: Specify testing approach** |
|
||||
|
||||
**Notes:**
|
||||
- Both bypass graceful shutdown procedures
|
||||
- May corrupt VM filesystem if used during write operations
|
||||
- Use `stop` action instead for graceful shutdown
|
||||
|
||||
---
|
||||
|
||||
### 3. Notifications (2 actions)
|
||||
|
||||
| Action | Description | Risk Level | Env Var Gate | Testing Strategy |
|
||||
|--------|-------------|------------|--------------|------------------|
|
||||
| `delete` | Permanently delete a notification | **HIGH** - Data loss, irreversible | `UNRAID_ALLOW_NOTIFICATIONS_DESTRUCTIVE` | **TODO: Specify testing approach** |
|
||||
| `delete_archived` | Permanently delete all archived notifications | **HIGH** - Bulk data loss, irreversible | `UNRAID_ALLOW_NOTIFICATIONS_DESTRUCTIVE` | **TODO: Specify testing approach** |
|
||||
|
||||
**Notes:**
|
||||
- Cannot recover deleted notifications
|
||||
- `delete_archived` affects ALL archived notifications (bulk operation)
|
||||
|
||||
---
|
||||
|
||||
### 4. Rclone (1 action)
|
||||
|
||||
| Action | Description | Risk Level | Env Var Gate | Testing Strategy |
|
||||
|--------|-------------|------------|--------------|------------------|
|
||||
| `delete_remote` | Permanently delete an rclone remote configuration | **HIGH** - Data loss, irreversible | `UNRAID_ALLOW_RCLONE_DESTRUCTIVE` | **TODO: Specify testing approach** |
|
||||
|
||||
**Notes:**
|
||||
- Removes cloud storage connection configuration
|
||||
- Does NOT delete data in the remote storage
|
||||
- Must reconfigure remote from scratch if deleted
|
||||
|
||||
---
|
||||
|
||||
### 5. Users (1 action)
|
||||
|
||||
| Action | Description | Risk Level | Env Var Gate | Testing Strategy |
|
||||
|--------|-------------|------------|--------------|------------------|
|
||||
| `delete` | Permanently delete a user account | **HIGH** - Data loss, irreversible | `UNRAID_ALLOW_USERS_DESTRUCTIVE` | **TODO: Specify testing approach** |
|
||||
|
||||
**Notes:**
|
||||
- Removes user account and permissions
|
||||
- Cannot delete the root user
|
||||
- User's data may remain but become orphaned
|
||||
|
||||
---
|
||||
|
||||
### 6. API Keys (1 action)
|
||||
|
||||
| Action | Description | Risk Level | Env Var Gate | Testing Strategy |
|
||||
|--------|-------------|------------|--------------|------------------|
|
||||
| `delete` | Permanently delete an API key | **HIGH** - Data loss, irreversible, breaks integrations | `UNRAID_ALLOW_KEYS_DESTRUCTIVE` | **TODO: Specify testing approach** |
|
||||
|
||||
**Notes:**
|
||||
- Immediately revokes API key access
|
||||
- Will break any integrations using the deleted key
|
||||
- Cannot be undone - must create new key
|
||||
|
||||
---
|
||||
|
||||
## Removed Actions (No Longer Exposed)
|
||||
|
||||
These actions were previously marked as destructive but have been **removed** from the array tool per the implementation plan:
|
||||
|
||||
| Action | Former Risk Level | Reason for Removal |
|
||||
|--------|-------------------|-------------------|
|
||||
| `start` | CRITICAL | System-wide impact - should not be exposed via MCP |
|
||||
| `stop` | CRITICAL | System-wide impact - should not be exposed via MCP |
|
||||
| `shutdown` | CRITICAL | System-wide impact - could cause data loss |
|
||||
| `reboot` | CRITICAL | System-wide impact - disrupts all services |
|
||||
|
||||
---
|
||||
|
||||
## Testing Strategy Options
|
||||
|
||||
Choose one of the following for each action in the "Testing Strategy" column:
|
||||
|
||||
### Option 1: Mock/Validation Only
|
||||
- Test parameter validation
|
||||
- Test `confirm=True` requirement
|
||||
- Test env var gate requirement
|
||||
- **DO NOT** execute the actual action
|
||||
|
||||
### Option 2: Dry-Run Testing
|
||||
- Test with `confirm=false` to verify rejection
|
||||
- Test without env var to verify gate
|
||||
- **DO NOT** execute with both gates passed
|
||||
|
||||
### Option 3: Test Server Execution
|
||||
- Execute on a dedicated test Unraid server (e.g., shart)
|
||||
- Requires pre-created test resources (containers, VMs, notifications)
|
||||
- Verify action succeeds and state changes as expected
|
||||
- Clean up after test
|
||||
|
||||
### Option 4: Manual Test Checklist
|
||||
- Document manual verification steps
|
||||
- Do not automate in mcporter suite
|
||||
- Requires human operator to execute and verify
|
||||
|
||||
### Option 5: Skip Testing
|
||||
- Too dangerous to automate
|
||||
- Rely on unit tests only
|
||||
- Document why testing is skipped
|
||||
|
||||
---
|
||||
|
||||
## Example Testing Strategies
|
||||
|
||||
**Safe approach (recommended for most):**
|
||||
```
|
||||
Option 1: Mock/Validation Only
|
||||
- Verify action requires UNRAID_ALLOW_DOCKER_DESTRUCTIVE=true
|
||||
- Verify action requires confirm=True
|
||||
- Do not execute actual deletion
|
||||
```
|
||||
|
||||
**Comprehensive approach (for test server only):**
|
||||
```
|
||||
Option 3: Test Server Execution on 'shart'
|
||||
- Create test container 'mcporter-test-container'
|
||||
- Execute remove with gates enabled
|
||||
- Verify container is deleted
|
||||
- Clean up not needed (container already removed)
|
||||
```
|
||||
|
||||
**Hybrid approach:**
|
||||
```
|
||||
Option 1 + Option 4: Mock validation + Manual checklist
|
||||
- Automated: Test gate requirements
|
||||
- Manual: Human operator verifies on test server
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Usage in mcporter Tests
|
||||
|
||||
Each tool test script will check the testing strategy:
|
||||
|
||||
```bash
|
||||
# Example from test_docker.sh
|
||||
test_remove_action() {
|
||||
local strategy="TODO: Specify testing approach" # From this file
|
||||
|
||||
case "$strategy" in
|
||||
*"Option 1"*|*"Mock"*)
|
||||
# Mock/validation testing
|
||||
test_remove_requires_env_var
|
||||
test_remove_requires_confirm
|
||||
;;
|
||||
*"Option 3"*|*"Test Server"*)
|
||||
# Real execution on test server
|
||||
if [[ "$UNRAID_TEST_SERVER" != "unraid-shart" ]]; then
|
||||
echo "SKIP: Destructive test only runs on test server"
|
||||
return 2
|
||||
fi
|
||||
test_remove_real_execution
|
||||
;;
|
||||
*"Option 5"*|*"Skip"*)
|
||||
echo "SKIP: Testing disabled for this action"
|
||||
return 2
|
||||
;;
|
||||
esac
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Security Model
|
||||
|
||||
**Two-tier security for destructive actions:**
|
||||
|
||||
1. **Environment Variable Gate** (first line of defense)
|
||||
- Must be explicitly enabled per tool
|
||||
- Defaults to disabled (safe)
|
||||
- Prevents accidental execution
|
||||
|
||||
2. **Runtime Confirmation** (second line of defense)
|
||||
- Must pass `confirm=True` in each call
|
||||
- Forces explicit acknowledgment per operation
|
||||
- Cannot be cached or preset
|
||||
|
||||
**Both must pass for execution.**
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. **Fill in Testing Strategy column** for each action above
|
||||
2. **Create test fixtures** if using Option 3 (test containers, VMs, etc.)
|
||||
3. **Implement tool test scripts** following the specified strategies
|
||||
4. **Document any special setup** required for destructive testing
|
||||
|
||||
---
|
||||
|
||||
## Questions to Consider
|
||||
|
||||
For each action, ask:
|
||||
- Is this safe to automate on a test server?
|
||||
- Do we have test fixtures/resources available?
|
||||
- What cleanup is required after testing?
|
||||
- What's the blast radius if something goes wrong?
|
||||
- Can we verify the action worked without side effects?
|
||||
|
||||
203
docs/MARKETPLACE.md
Normal file
203
docs/MARKETPLACE.md
Normal file
@@ -0,0 +1,203 @@
|
||||
# Claude Code Marketplace Setup
|
||||
|
||||
This document explains the Claude Code marketplace and plugin structure for the Unraid MCP project.
|
||||
|
||||
## What Was Created
|
||||
|
||||
### 1. Marketplace Manifest (`.claude-plugin/marketplace.json`)
|
||||
The marketplace catalog that lists all available plugins in this repository.
|
||||
|
||||
**Location:** `.claude-plugin/marketplace.json`
|
||||
|
||||
**Contents:**
|
||||
- Marketplace metadata (name, version, owner, repository)
|
||||
- Plugin catalog with the "unraid" skill
|
||||
- Categories and tags for discoverability
|
||||
|
||||
### 2. Plugin Manifest (`skills/unraid/.claude-plugin/plugin.json`)
|
||||
The individual plugin configuration for the Unraid skill.
|
||||
|
||||
**Location:** `skills/unraid/.claude-plugin/plugin.json`
|
||||
|
||||
**Contents:**
|
||||
- Plugin name, version, author
|
||||
- Repository and homepage links
|
||||
- Plugin-specific metadata
|
||||
|
||||
### 3. Documentation
|
||||
- `.claude-plugin/README.md` - Marketplace installation guide
|
||||
- Updated root `README.md` with plugin installation section
|
||||
|
||||
### 4. Validation Script
|
||||
- `scripts/validate-marketplace.sh` - Automated validation of marketplace structure
|
||||
|
||||
## Installation Methods
|
||||
|
||||
### Method 1: GitHub Distribution (Recommended for Users)
|
||||
|
||||
Once you push this to GitHub, users can install via:
|
||||
|
||||
```bash
|
||||
# Add your marketplace
|
||||
/plugin marketplace add jmagar/unraid-mcp
|
||||
|
||||
# Install the Unraid skill
|
||||
/plugin install unraid @unraid-mcp
|
||||
```
|
||||
|
||||
### Method 2: Local Installation (Development)
|
||||
|
||||
For testing locally before publishing:
|
||||
|
||||
```bash
|
||||
# Add local marketplace
|
||||
/plugin marketplace add /home/jmagar/workspace/unraid-mcp
|
||||
|
||||
# Install the plugin
|
||||
/plugin install unraid @unraid-mcp
|
||||
```
|
||||
|
||||
### Method 3: Direct URL
|
||||
|
||||
Users can also install from a specific commit or branch:
|
||||
|
||||
```bash
|
||||
# From specific branch
|
||||
/plugin marketplace add jmagar/unraid-mcp#main
|
||||
|
||||
# From specific commit
|
||||
/plugin marketplace add jmagar/unraid-mcp#abc123
|
||||
```
|
||||
|
||||
## Plugin Structure
|
||||
|
||||
```
|
||||
unraid-mcp/
|
||||
├── .claude-plugin/ # Marketplace manifest
|
||||
│ ├── marketplace.json
|
||||
│ └── README.md
|
||||
├── skills/unraid/ # Plugin directory
|
||||
│ ├── .claude-plugin/ # Plugin manifest
|
||||
│ │ └── plugin.json
|
||||
│ ├── SKILL.md # Skill documentation
|
||||
│ ├── README.md # Plugin documentation
|
||||
│ ├── examples/ # Example scripts
|
||||
│ ├── scripts/ # Helper scripts
|
||||
│ └── references/ # API reference docs
|
||||
└── scripts/
|
||||
└── validate-marketplace.sh # Validation tool
|
||||
```
|
||||
|
||||
## Marketplace Metadata
|
||||
|
||||
### Categories
|
||||
- `infrastructure` - Server management and monitoring tools
|
||||
|
||||
### Tags
|
||||
- `unraid` - Unraid-specific functionality
|
||||
- `monitoring` - System monitoring capabilities
|
||||
- `homelab` - Homelab automation
|
||||
- `graphql` - GraphQL API integration
|
||||
- `docker` - Docker container management
|
||||
- `virtualization` - VM management
|
||||
|
||||
## Publishing Checklist
|
||||
|
||||
Before publishing to GitHub:
|
||||
|
||||
1. **Validate Structure**
|
||||
```bash
|
||||
./scripts/validate-marketplace.sh
|
||||
```
|
||||
|
||||
2. **Update Version Numbers**
|
||||
- Bump version in `.claude-plugin/marketplace.json`
|
||||
- Bump version in `skills/unraid/.claude-plugin/plugin.json`
|
||||
- Update version in `README.md` if needed
|
||||
|
||||
3. **Test Locally**
|
||||
```bash
|
||||
/plugin marketplace add .
|
||||
/plugin install unraid @unraid-mcp
|
||||
```
|
||||
|
||||
4. **Commit and Push**
|
||||
```bash
|
||||
git add .claude-plugin/ skills/unraid/.claude-plugin/
|
||||
git commit -m "feat: add Claude Code marketplace configuration"
|
||||
git push origin main
|
||||
```
|
||||
|
||||
5. **Create Release Tag** (Optional)
|
||||
```bash
|
||||
git tag -a v0.2.0 -m "Release v0.2.0"
|
||||
git push origin v0.2.0
|
||||
```
|
||||
|
||||
## User Experience
|
||||
|
||||
After installation, users will:
|
||||
|
||||
1. **See the skill in their skill list**
|
||||
```bash
|
||||
/skill list
|
||||
```
|
||||
|
||||
2. **Access Unraid functionality directly**
|
||||
- Claude Code will automatically detect when to invoke the skill
|
||||
- Users can explicitly invoke with `/unraid`
|
||||
|
||||
3. **Have access to all helper scripts**
|
||||
- Example scripts in `examples/`
|
||||
- Utility scripts in `scripts/`
|
||||
- API reference in `references/`
|
||||
|
||||
## Maintenance
|
||||
|
||||
### Updating the Plugin
|
||||
|
||||
To release a new version:
|
||||
|
||||
1. Make changes to the plugin
|
||||
2. Update version in `skills/unraid/.claude-plugin/plugin.json`
|
||||
3. Update marketplace catalog in `.claude-plugin/marketplace.json`
|
||||
4. Run validation: `./scripts/validate-marketplace.sh`
|
||||
5. Commit and push
|
||||
|
||||
Users with the plugin installed will see the update available and can upgrade with:
|
||||
```bash
|
||||
/plugin update unraid
|
||||
```
|
||||
|
||||
### Adding More Plugins
|
||||
|
||||
To add additional plugins to this marketplace:
|
||||
|
||||
1. Create new plugin directory: `skills/new-plugin/`
|
||||
2. Add plugin manifest: `skills/new-plugin/.claude-plugin/plugin.json`
|
||||
3. Update marketplace catalog: add entry to `.plugins[]` array in `.claude-plugin/marketplace.json`
|
||||
4. Validate: `./scripts/validate-marketplace.sh`
|
||||
|
||||
## Support
|
||||
|
||||
- **Repository:** https://github.com/jmagar/unraid-mcp
|
||||
- **Issues:** https://github.com/jmagar/unraid-mcp/issues
|
||||
- **Documentation:** See `.claude-plugin/README.md` and `skills/unraid/README.md`
|
||||
|
||||
## Validation
|
||||
|
||||
Run the validation script anytime to ensure marketplace integrity:
|
||||
|
||||
```bash
|
||||
./scripts/validate-marketplace.sh
|
||||
```
|
||||
|
||||
This checks:
|
||||
- Manifest file existence and validity
|
||||
- JSON syntax
|
||||
- Required fields
|
||||
- Plugin structure
|
||||
- Source path accuracy
|
||||
- Documentation completeness
|
||||
|
||||
All 17 checks must pass before publishing.
|
||||
218
docs/PUBLISHING.md
Normal file
218
docs/PUBLISHING.md
Normal file
@@ -0,0 +1,218 @@
|
||||
# Publishing Guide for unraid-mcp
|
||||
|
||||
This guide covers how to publish `unraid-mcp` to PyPI so it can be installed via `uvx` or `pip` from anywhere.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
1. **PyPI Account**: Create accounts on both:
|
||||
- [Test PyPI](https://test.pypi.org/account/register/) (for testing)
|
||||
- [PyPI](https://pypi.org/account/register/) (for production)
|
||||
|
||||
2. **API Tokens**: Generate API tokens for automated publishing:
|
||||
- Test PyPI: https://test.pypi.org/manage/account/token/
|
||||
- PyPI: https://pypi.org/manage/account/token/
|
||||
|
||||
3. **Save Tokens Securely**:
|
||||
```bash
|
||||
# Add to ~/.pypirc (never commit this file!)
|
||||
cat > ~/.pypirc << 'EOF'
|
||||
[distutils]
|
||||
index-servers =
|
||||
pypi
|
||||
testpypi
|
||||
|
||||
[pypi]
|
||||
username = __token__
|
||||
password = pypi-YOUR-API-TOKEN-HERE
|
||||
|
||||
[testpypi]
|
||||
username = __token__
|
||||
password = pypi-YOUR-TEST-API-TOKEN-HERE
|
||||
repository = https://test.pypi.org/legacy/
|
||||
EOF
|
||||
|
||||
chmod 600 ~/.pypirc # Secure the file
|
||||
```
|
||||
|
||||
## Version Management
|
||||
|
||||
Before publishing, update the version in `pyproject.toml`:
|
||||
|
||||
```toml
|
||||
[project]
|
||||
version = "0.2.1" # Follow semantic versioning: MAJOR.MINOR.PATCH
|
||||
```
|
||||
|
||||
**Semantic Versioning Guide:**
|
||||
- **MAJOR** (1.0.0): Breaking changes
|
||||
- **MINOR** (0.2.0): New features (backward compatible)
|
||||
- **PATCH** (0.2.1): Bug fixes (backward compatible)
|
||||
|
||||
## Publishing Workflow
|
||||
|
||||
### 1. Clean Previous Builds
|
||||
|
||||
```bash
|
||||
# Remove old build artifacts
|
||||
rm -rf dist/ build/ *.egg-info/
|
||||
```
|
||||
|
||||
### 2. Run Quality Checks
|
||||
|
||||
```bash
|
||||
# Lint and format code
|
||||
uv run ruff check unraid_mcp/
|
||||
uv run ruff format unraid_mcp/
|
||||
|
||||
# Type check
|
||||
uv run ty check unraid_mcp/
|
||||
|
||||
# Run tests
|
||||
uv run pytest
|
||||
|
||||
# Check coverage
|
||||
uv run pytest --cov=unraid_mcp --cov-report=html
|
||||
```
|
||||
|
||||
### 3. Build the Package
|
||||
|
||||
```bash
|
||||
# Build both wheel and source distribution
|
||||
uv run python -m build
|
||||
```
|
||||
|
||||
This creates:
|
||||
- `dist/unraid_mcp-VERSION-py3-none-any.whl` (wheel)
|
||||
- `dist/unraid_mcp-VERSION.tar.gz` (source distribution)
|
||||
|
||||
### 4. Validate the Package
|
||||
|
||||
```bash
|
||||
# Check that the package meets PyPI requirements
|
||||
uv run twine check dist/*
|
||||
```
|
||||
|
||||
Expected output: `PASSED` for both files.
|
||||
|
||||
### 5. Test on Test PyPI (IMPORTANT!)
|
||||
|
||||
Always test on Test PyPI first:
|
||||
|
||||
```bash
|
||||
# Upload to Test PyPI
|
||||
uv run twine upload --repository testpypi dist/*
|
||||
|
||||
# Test installation from Test PyPI
|
||||
uvx --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ unraid-mcp-server
|
||||
|
||||
# Or with pip in a test environment
|
||||
pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ unraid-mcp
|
||||
```
|
||||
|
||||
**Note**: `--extra-index-url https://pypi.org/simple/` is needed because dependencies come from production PyPI.
|
||||
|
||||
### 6. Publish to PyPI (Production)
|
||||
|
||||
Once testing passes:
|
||||
|
||||
```bash
|
||||
# Upload to production PyPI
|
||||
uv run twine upload dist/*
|
||||
```
|
||||
|
||||
### 7. Verify Installation
|
||||
|
||||
```bash
|
||||
# Install and run from PyPI using uvx (no installation required!)
|
||||
uvx unraid-mcp-server --help
|
||||
|
||||
# Or install globally
|
||||
uv tool install unraid-mcp
|
||||
|
||||
# Or install in a project
|
||||
uv add unraid-mcp
|
||||
```
|
||||
|
||||
## Post-Publishing Checklist
|
||||
|
||||
- [ ] Create a GitHub Release with the same version tag
|
||||
- [ ] Update CHANGELOG.md with release notes
|
||||
- [ ] Test installation on a fresh machine
|
||||
- [ ] Update documentation if API changed
|
||||
- [ ] Announce release (if applicable)
|
||||
|
||||
## Running from Any Machine with uvx
|
||||
|
||||
Once published to PyPI, users can run the server without installing:
|
||||
|
||||
```bash
|
||||
# Run directly with uvx (recommended)
|
||||
uvx unraid-mcp-server
|
||||
|
||||
# Or with custom environment variables
|
||||
UNRAID_API_URL=https://your-server uvx unraid-mcp-server
|
||||
```
|
||||
|
||||
**Benefits of uvx:**
|
||||
- No installation required
|
||||
- Automatic virtual environment management
|
||||
- Always uses the latest version (or specify version: `uvx unraid-mcp-server@0.2.0`)
|
||||
- Clean execution environment
|
||||
|
||||
## Automation with GitHub Actions (Future)
|
||||
|
||||
Consider adding `.github/workflows/publish.yml`:
|
||||
|
||||
```yaml
|
||||
name: Publish to PyPI
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: astral-sh/setup-uv@v4
|
||||
- name: Build package
|
||||
run: uv run python -m build
|
||||
- name: Publish to PyPI
|
||||
env:
|
||||
TWINE_USERNAME: __token__
|
||||
TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
|
||||
run: uv run twine upload dist/*
|
||||
```
|
||||
|
||||
> **Tip:** Consider using [PyPI Trusted Publishing](https://docs.pypi.org/trusted-publishers/) instead of API token secrets. Trusted Publishing uses OpenID Connect (OIDC) to authenticate directly from GitHub Actions without storing long-lived secrets.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "File already exists" Error
|
||||
|
||||
PyPI doesn't allow re-uploading the same version. Options:
|
||||
1. Increment version number in `pyproject.toml`
|
||||
2. Delete old dist files and rebuild
|
||||
|
||||
### Missing Dependencies
|
||||
|
||||
If installation fails due to missing dependencies:
|
||||
1. Check that all dependencies are in `pyproject.toml` `dependencies` section
|
||||
2. Ensure dependency version constraints are correct
|
||||
3. Test in a clean virtual environment
|
||||
|
||||
### Import Errors After Installation
|
||||
|
||||
If the package installs but imports fail:
|
||||
1. Verify package structure in wheel: `unzip -l dist/*.whl`
|
||||
2. Check that `__init__.py` files exist in all package directories
|
||||
3. Ensure `packages = ["unraid_mcp"]` in `[tool.hatch.build.targets.wheel]`
|
||||
|
||||
## Resources
|
||||
|
||||
- [PyPI Publishing Guide](https://packaging.python.org/tutorials/packaging-projects/)
|
||||
- [Semantic Versioning](https://semver.org/)
|
||||
- [Python Packaging User Guide](https://packaging.python.org/)
|
||||
- [uv Documentation](https://docs.astral.sh/uv/)
|
||||
- [Twine Documentation](https://twine.readthedocs.io/)
|
||||
2393
docs/UNRAID_API_COMPLETE_REFERENCE.md
Normal file
2393
docs/UNRAID_API_COMPLETE_REFERENCE.md
Normal file
File diff suppressed because it is too large
Load Diff
290
docs/UNRAID_API_OPERATIONS.md
Normal file
290
docs/UNRAID_API_OPERATIONS.md
Normal file
@@ -0,0 +1,290 @@
|
||||
# Unraid GraphQL API Operations
|
||||
|
||||
Generated via live introspection at `2026-02-15 23:45:50Z`.
|
||||
|
||||
## Schema Summary
|
||||
- Query root: `Query`
|
||||
- Mutation root: `Mutation`
|
||||
- Subscription root: `Subscription`
|
||||
- Total types: **164**
|
||||
- Total directives: **6**
|
||||
- Type kinds:
|
||||
- `ENUM`: 32
|
||||
- `INPUT_OBJECT`: 16
|
||||
- `INTERFACE`: 2
|
||||
- `OBJECT`: 103
|
||||
- `SCALAR`: 10
|
||||
- `UNION`: 1
|
||||
|
||||
## Queries
|
||||
Total: **46**
|
||||
|
||||
### `apiKey(id: PrefixedID!): ApiKey`
|
||||
#### Required Permissions: - Action: **READ_ANY** - Resource: **API_KEY**
|
||||
|
||||
Arguments:
|
||||
- `id`: `PrefixedID!`
|
||||
|
||||
### `apiKeyPossiblePermissions(): [Permission!]!`
|
||||
#### Required Permissions: - Action: **READ_ANY** - Resource: **PERMISSION** #### Description: All possible permissions for API keys
|
||||
|
||||
### `apiKeyPossibleRoles(): [Role!]!`
|
||||
#### Required Permissions: - Action: **READ_ANY** - Resource: **PERMISSION** #### Description: All possible roles for API keys
|
||||
|
||||
### `apiKeys(): [ApiKey!]!`
|
||||
#### Required Permissions: - Action: **READ_ANY** - Resource: **API_KEY**
|
||||
|
||||
### `array(): UnraidArray!`
|
||||
#### Required Permissions: - Action: **READ_ANY** - Resource: **ARRAY**
|
||||
|
||||
### `config(): Config!`
|
||||
#### Required Permissions: - Action: **READ_ANY** - Resource: **CONFIG**
|
||||
|
||||
### `customization(): Customization`
|
||||
#### Required Permissions: - Action: **READ_ANY** - Resource: **CUSTOMIZATIONS**
|
||||
|
||||
### `disk(id: PrefixedID!): Disk!`
|
||||
#### Required Permissions: - Action: **READ_ANY** - Resource: **DISK**
|
||||
|
||||
Arguments:
|
||||
- `id`: `PrefixedID!`
|
||||
|
||||
### `disks(): [Disk!]!`
|
||||
#### Required Permissions: - Action: **READ_ANY** - Resource: **DISK**
|
||||
|
||||
### `docker(): Docker!`
|
||||
#### Required Permissions: - Action: **READ_ANY** - Resource: **DOCKER**
|
||||
|
||||
### `flash(): Flash!`
|
||||
#### Required Permissions: - Action: **READ_ANY** - Resource: **FLASH**
|
||||
|
||||
### `getApiKeyCreationFormSchema(): ApiKeyFormSettings!`
|
||||
#### Required Permissions: - Action: **READ_ANY** - Resource: **API_KEY** #### Description: Get JSON Schema for API key creation form
|
||||
|
||||
### `getAvailableAuthActions(): [AuthAction!]!`
|
||||
Get all available authentication actions with possession
|
||||
|
||||
### `getPermissionsForRoles(roles: [Role!]!): [Permission!]!`
|
||||
#### Required Permissions: - Action: **READ_ANY** - Resource: **PERMISSION** #### Description: Get the actual permissions that would be granted by a set of roles
|
||||
|
||||
Arguments:
|
||||
- `roles`: `[Role!]!`
|
||||
|
||||
### `info(): Info!`
|
||||
#### Required Permissions: - Action: **READ_ANY** - Resource: **INFO**
|
||||
|
||||
### `isInitialSetup(): Boolean!`
|
||||
### `isSSOEnabled(): Boolean!`
|
||||
### `logFile(lines: Int, path: String!, startLine: Int): LogFileContent!`
|
||||
#### Required Permissions: - Action: **READ_ANY** - Resource: **LOGS**
|
||||
|
||||
Arguments:
|
||||
- `lines`: `Int`
|
||||
- `path`: `String!`
|
||||
- `startLine`: `Int`
|
||||
|
||||
### `logFiles(): [LogFile!]!`
|
||||
#### Required Permissions: - Action: **READ_ANY** - Resource: **LOGS**
|
||||
|
||||
### `me(): UserAccount!`
|
||||
#### Required Permissions: - Action: **READ_ANY** - Resource: **ME**
|
||||
|
||||
### `metrics(): Metrics!`
|
||||
#### Required Permissions: - Action: **READ_ANY** - Resource: **INFO**
|
||||
|
||||
### `notifications(): Notifications!`
|
||||
#### Required Permissions: - Action: **READ_ANY** - Resource: **NOTIFICATIONS** #### Description: Get all notifications
|
||||
|
||||
### `oidcConfiguration(): OidcConfiguration!`
|
||||
#### Required Permissions: - Action: **READ_ANY** - Resource: **CONFIG** #### Description: Get the full OIDC configuration (admin only)
|
||||
|
||||
### `oidcProvider(id: PrefixedID!): OidcProvider`
|
||||
#### Required Permissions: - Action: **READ_ANY** - Resource: **CONFIG** #### Description: Get a specific OIDC provider by ID
|
||||
|
||||
Arguments:
|
||||
- `id`: `PrefixedID!`
|
||||
|
||||
### `oidcProviders(): [OidcProvider!]!`
|
||||
#### Required Permissions: - Action: **READ_ANY** - Resource: **CONFIG** #### Description: Get all configured OIDC providers (admin only)
|
||||
|
||||
### `online(): Boolean!`
|
||||
#### Required Permissions: - Action: **READ_ANY** - Resource: **ONLINE**
|
||||
|
||||
### `owner(): Owner!`
|
||||
#### Required Permissions: - Action: **READ_ANY** - Resource: **OWNER**
|
||||
|
||||
### `parityHistory(): [ParityCheck!]!`
|
||||
#### Required Permissions: - Action: **READ_ANY** - Resource: **ARRAY**
|
||||
|
||||
### `plugins(): [Plugin!]!`
|
||||
#### Required Permissions: - Action: **READ_ANY** - Resource: **CONFIG** #### Description: List all installed plugins with their metadata
|
||||
|
||||
### `previewEffectivePermissions(permissions: [AddPermissionInput!], roles: [Role!]): [Permission!]!`
|
||||
#### Required Permissions: - Action: **READ_ANY** - Resource: **PERMISSION** #### Description: Preview the effective permissions for a combination of roles and explicit permissions
|
||||
|
||||
Arguments:
|
||||
- `permissions`: `[AddPermissionInput!]`
|
||||
- `roles`: `[Role!]`
|
||||
|
||||
### `publicOidcProviders(): [PublicOidcProvider!]!`
|
||||
Get public OIDC provider information for login buttons
|
||||
|
||||
### `publicPartnerInfo(): PublicPartnerInfo`
|
||||
### `publicTheme(): Theme!`
|
||||
### `rclone(): RCloneBackupSettings!`
|
||||
#### Required Permissions: - Action: **READ_ANY** - Resource: **FLASH**
|
||||
|
||||
### `registration(): Registration`
|
||||
#### Required Permissions: - Action: **READ_ANY** - Resource: **REGISTRATION**
|
||||
|
||||
### `server(): Server`
|
||||
#### Required Permissions: - Action: **READ_ANY** - Resource: **SERVERS**
|
||||
|
||||
### `servers(): [Server!]!`
|
||||
#### Required Permissions: - Action: **READ_ANY** - Resource: **SERVERS**
|
||||
|
||||
### `services(): [Service!]!`
|
||||
#### Required Permissions: - Action: **READ_ANY** - Resource: **SERVICES**
|
||||
|
||||
### `settings(): Settings!`
|
||||
### `shares(): [Share!]!`
|
||||
#### Required Permissions: - Action: **READ_ANY** - Resource: **SHARE**
|
||||
|
||||
### `upsConfiguration(): UPSConfiguration!`
|
||||
### `upsDeviceById(id: String!): UPSDevice`
|
||||
Arguments:
|
||||
- `id`: `String!`
|
||||
|
||||
### `upsDevices(): [UPSDevice!]!`
|
||||
### `validateOidcSession(token: String!): OidcSessionValidation!`
|
||||
#### Required Permissions: - Action: **READ_ANY** - Resource: **CONFIG** #### Description: Validate an OIDC session token (internal use for CLI validation)
|
||||
|
||||
Arguments:
|
||||
- `token`: `String!`
|
||||
|
||||
### `vars(): Vars!`
|
||||
#### Required Permissions: - Action: **READ_ANY** - Resource: **VARS**
|
||||
|
||||
### `vms(): Vms!`
|
||||
#### Required Permissions: - Action: **READ_ANY** - Resource: **VMS** #### Description: Get information about all VMs on the system
|
||||
|
||||
## Mutations
|
||||
Total: **22**
|
||||
|
||||
### `addPlugin(input: PluginManagementInput!): Boolean!`
|
||||
#### Required Permissions: - Action: **UPDATE_ANY** - Resource: **CONFIG** #### Description: Add one or more plugins to the API. Returns false if restart was triggered automatically, true if manual restart is required.
|
||||
|
||||
Arguments:
|
||||
- `input`: `PluginManagementInput!`
|
||||
|
||||
### `apiKey(): ApiKeyMutations!`
|
||||
### `archiveAll(importance: NotificationImportance): NotificationOverview!`
|
||||
Arguments:
|
||||
- `importance`: `NotificationImportance`
|
||||
|
||||
### `archiveNotification(id: PrefixedID!): Notification!`
|
||||
Marks a notification as archived.
|
||||
|
||||
Arguments:
|
||||
- `id`: `PrefixedID!`
|
||||
|
||||
### `archiveNotifications(ids: [PrefixedID!]!): NotificationOverview!`
|
||||
Arguments:
|
||||
- `ids`: `[PrefixedID!]!`
|
||||
|
||||
### `array(): ArrayMutations!`
|
||||
### `configureUps(config: UPSConfigInput!): Boolean!`
|
||||
Arguments:
|
||||
- `config`: `UPSConfigInput!`
|
||||
|
||||
### `createNotification(input: NotificationData!): Notification!`
|
||||
Creates a new notification record
|
||||
|
||||
Arguments:
|
||||
- `input`: `NotificationData!`
|
||||
|
||||
### `customization(): CustomizationMutations!`
|
||||
### `deleteArchivedNotifications(): NotificationOverview!`
|
||||
Deletes all archived notifications on server.
|
||||
|
||||
### `deleteNotification(id: PrefixedID!, type: NotificationType!): NotificationOverview!`
|
||||
Arguments:
|
||||
- `id`: `PrefixedID!`
|
||||
- `type`: `NotificationType!`
|
||||
|
||||
### `docker(): DockerMutations!`
|
||||
### `initiateFlashBackup(input: InitiateFlashBackupInput!): FlashBackupStatus!`
|
||||
Initiates a flash drive backup using a configured remote.
|
||||
|
||||
Arguments:
|
||||
- `input`: `InitiateFlashBackupInput!`
|
||||
|
||||
### `parityCheck(): ParityCheckMutations!`
|
||||
### `rclone(): RCloneMutations!`
|
||||
### `recalculateOverview(): NotificationOverview!`
|
||||
Reads each notification to recompute & update the overview.
|
||||
|
||||
### `removePlugin(input: PluginManagementInput!): Boolean!`
|
||||
#### Required Permissions: - Action: **DELETE_ANY** - Resource: **CONFIG** #### Description: Remove one or more plugins from the API. Returns false if restart was triggered automatically, true if manual restart is required.
|
||||
|
||||
Arguments:
|
||||
- `input`: `PluginManagementInput!`
|
||||
|
||||
### `unarchiveAll(importance: NotificationImportance): NotificationOverview!`
|
||||
Arguments:
|
||||
- `importance`: `NotificationImportance`
|
||||
|
||||
### `unarchiveNotifications(ids: [PrefixedID!]!): NotificationOverview!`
|
||||
Arguments:
|
||||
- `ids`: `[PrefixedID!]!`
|
||||
|
||||
### `unreadNotification(id: PrefixedID!): Notification!`
|
||||
Marks a notification as unread.
|
||||
|
||||
Arguments:
|
||||
- `id`: `PrefixedID!`
|
||||
|
||||
### `updateSettings(input: JSON!): UpdateSettingsResponse!`
|
||||
#### Required Permissions: - Action: **UPDATE_ANY** - Resource: **CONFIG**
|
||||
|
||||
Arguments:
|
||||
- `input`: `JSON!`
|
||||
|
||||
### `vm(): VmMutations!`
|
||||
## Subscriptions
|
||||
Total: **11**
|
||||
|
||||
### `arraySubscription(): UnraidArray!`
|
||||
#### Required Permissions: - Action: **READ_ANY** - Resource: **ARRAY**
|
||||
|
||||
### `logFile(path: String!): LogFileContent!`
|
||||
#### Required Permissions: - Action: **READ_ANY** - Resource: **LOGS**
|
||||
|
||||
Arguments:
|
||||
- `path`: `String!`
|
||||
|
||||
### `notificationAdded(): Notification!`
|
||||
#### Required Permissions: - Action: **READ_ANY** - Resource: **NOTIFICATIONS**
|
||||
|
||||
### `notificationsOverview(): NotificationOverview!`
|
||||
#### Required Permissions: - Action: **READ_ANY** - Resource: **NOTIFICATIONS**
|
||||
|
||||
### `ownerSubscription(): Owner!`
|
||||
#### Required Permissions: - Action: **READ_ANY** - Resource: **OWNER**
|
||||
|
||||
### `parityHistorySubscription(): ParityCheck!`
|
||||
#### Required Permissions: - Action: **READ_ANY** - Resource: **ARRAY**
|
||||
|
||||
### `serversSubscription(): Server!`
|
||||
#### Required Permissions: - Action: **READ_ANY** - Resource: **SERVERS**
|
||||
|
||||
### `systemMetricsCpu(): CpuUtilization!`
|
||||
#### Required Permissions: - Action: **READ_ANY** - Resource: **INFO**
|
||||
|
||||
### `systemMetricsCpuTelemetry(): CpuPackages!`
|
||||
#### Required Permissions: - Action: **READ_ANY** - Resource: **INFO**
|
||||
|
||||
### `systemMetricsMemory(): MemoryUtilization!`
|
||||
#### Required Permissions: - Action: **READ_ANY** - Resource: **INFO**
|
||||
|
||||
### `upsUpdates(): UPSDevice!`
|
||||
Reference in New Issue
Block a user