proxmox-aiops 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. proxmox_aiops-0.1.0/.gitignore +22 -0
  2. proxmox_aiops-0.1.0/LICENSE +21 -0
  3. proxmox_aiops-0.1.0/PKG-INFO +70 -0
  4. proxmox_aiops-0.1.0/README.md +54 -0
  5. proxmox_aiops-0.1.0/RELEASE_NOTES.md +33 -0
  6. proxmox_aiops-0.1.0/SECURITY.md +63 -0
  7. proxmox_aiops-0.1.0/mcp_server/__init__.py +1 -0
  8. proxmox_aiops-0.1.0/mcp_server/_shared.py +102 -0
  9. proxmox_aiops-0.1.0/mcp_server/server.py +28 -0
  10. proxmox_aiops-0.1.0/mcp_server/tools/__init__.py +1 -0
  11. proxmox_aiops-0.1.0/mcp_server/tools/cluster.py +51 -0
  12. proxmox_aiops-0.1.0/mcp_server/tools/lxc.py +64 -0
  13. proxmox_aiops-0.1.0/mcp_server/tools/storage.py +43 -0
  14. proxmox_aiops-0.1.0/mcp_server/tools/vm.py +353 -0
  15. proxmox_aiops-0.1.0/proxmox_aiops/__init__.py +9 -0
  16. proxmox_aiops-0.1.0/proxmox_aiops/cli/__init__.py +9 -0
  17. proxmox_aiops-0.1.0/proxmox_aiops/cli/_common.py +81 -0
  18. proxmox_aiops-0.1.0/proxmox_aiops/cli/_root.py +54 -0
  19. proxmox_aiops-0.1.0/proxmox_aiops/cli/cluster.py +49 -0
  20. proxmox_aiops-0.1.0/proxmox_aiops/cli/doctor.py +21 -0
  21. proxmox_aiops-0.1.0/proxmox_aiops/cli/lxc.py +62 -0
  22. proxmox_aiops-0.1.0/proxmox_aiops/cli/storage.py +51 -0
  23. proxmox_aiops-0.1.0/proxmox_aiops/cli/vm.py +250 -0
  24. proxmox_aiops-0.1.0/proxmox_aiops/config.py +134 -0
  25. proxmox_aiops-0.1.0/proxmox_aiops/connection.py +101 -0
  26. proxmox_aiops-0.1.0/proxmox_aiops/doctor.py +65 -0
  27. proxmox_aiops-0.1.0/proxmox_aiops/governance/__init__.py +40 -0
  28. proxmox_aiops-0.1.0/proxmox_aiops/governance/audit.py +377 -0
  29. proxmox_aiops-0.1.0/proxmox_aiops/governance/budget.py +225 -0
  30. proxmox_aiops-0.1.0/proxmox_aiops/governance/decorators.py +474 -0
  31. proxmox_aiops-0.1.0/proxmox_aiops/governance/paths.py +23 -0
  32. proxmox_aiops-0.1.0/proxmox_aiops/governance/patterns.py +378 -0
  33. proxmox_aiops-0.1.0/proxmox_aiops/governance/policy.py +411 -0
  34. proxmox_aiops-0.1.0/proxmox_aiops/governance/sanitize.py +39 -0
  35. proxmox_aiops-0.1.0/proxmox_aiops/governance/undo.py +218 -0
  36. proxmox_aiops-0.1.0/proxmox_aiops/ops/__init__.py +1 -0
  37. proxmox_aiops-0.1.0/proxmox_aiops/ops/cluster.py +82 -0
  38. proxmox_aiops-0.1.0/proxmox_aiops/ops/lxc.py +69 -0
  39. proxmox_aiops-0.1.0/proxmox_aiops/ops/storage.py +71 -0
  40. proxmox_aiops-0.1.0/proxmox_aiops/ops/vm_lifecycle.py +247 -0
  41. proxmox_aiops-0.1.0/pyproject.toml +59 -0
  42. proxmox_aiops-0.1.0/server.json +21 -0
  43. proxmox_aiops-0.1.0/skills/proxmox-aiops/SKILL.md +143 -0
  44. proxmox_aiops-0.1.0/skills/proxmox-aiops/references/capabilities.md +60 -0
  45. proxmox_aiops-0.1.0/skills/proxmox-aiops/references/cli-reference.md +62 -0
  46. proxmox_aiops-0.1.0/skills/proxmox-aiops/references/setup-guide.md +74 -0
  47. proxmox_aiops-0.1.0/tests/test_smoke.py +222 -0
@@ -0,0 +1,22 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ .pytest_cache/
6
+ .ruff_cache/
7
+
8
+ # Virtual envs / build
9
+ .venv/
10
+ dist/
11
+ build/
12
+
13
+ # uv
14
+ uv.lock
15
+
16
+ # Local config / secrets (never commit)
17
+ *.env
18
+ .env
19
+ config.yaml
20
+
21
+ # OS
22
+ .DS_Store
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 wei <zhouwei008@gmail.com>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,70 @@
1
+ Metadata-Version: 2.4
2
+ Name: proxmox-aiops
3
+ Version: 0.1.0
4
+ Summary: Proxmox VE AI-powered VM/container lifecycle operations with a built-in governance harness (audit, budget, undo, risk tiers)
5
+ Author-email: wei <zhouwei008@gmail.com>
6
+ License-Expression: MIT
7
+ License-File: LICENSE
8
+ Requires-Python: >=3.11
9
+ Requires-Dist: mcp[cli]<2.0,>=1.10
10
+ Requires-Dist: proxmoxer<3.0,>=2.0
11
+ Requires-Dist: python-dotenv<2.0,>=1.0
12
+ Requires-Dist: pyyaml<7.0,>=6.0
13
+ Requires-Dist: rich<16.0,>=13.0
14
+ Requires-Dist: typer<1.0,>=0.12
15
+ Description-Content-Type: text/markdown
16
+
17
+ <!-- mcp-name: io.github.AIops-tools/proxmox-aiops -->
18
+
19
+ # Proxmox AIops (preview)
20
+
21
+ > **Disclaimer**: Community-maintained open-source project. **Not affiliated with, endorsed by, or sponsored by Proxmox Server Solutions GmbH.** "Proxmox" is a trademark of its owner. MIT licensed.
22
+
23
+ AI-powered Proxmox VE VM and container lifecycle operations with a **built-in
24
+ governance harness** — unified audit log, policy engine, token/runaway budget
25
+ guard, undo-token recording, and graduated-autonomy risk tiers. Self-contained:
26
+ no external dependencies beyond `proxmoxer` and the MCP SDK. Preview — not yet
27
+ full coverage of every Proxmox operation.
28
+
29
+ ## What works
30
+
31
+ - **CLI** (`proxmox-aiops ...`): `vm list/get/config/start/stop/shutdown/reboot/reconfigure/clone/delete/migrate`, `vm snapshot-create/snapshot-delete/snapshot-list/snapshot-rollback`, `ct list/start/stop`, `cluster nodes/status/task-status`, `storage list/content`, `doctor`, `mcp`.
32
+ - **MCP server** (`proxmox-aiops mcp` or `proxmox-aiops-mcp`): **23 tools**, every one wrapped with the bundled `@governed_tool` harness.
33
+ - **Reversibility**: write ops with a clean inverse (start/stop/shutdown/reconfigure/clone/migrate/snapshot-create, container start/stop) record an inverse undo descriptor; irreversible ops (delete, snapshot-rollback) declare none and are tagged `high` risk.
34
+ - **Async tasks**: Proxmox writes return a task UPID — poll completion with `cluster task-status` (the runaway budget guard prevents poll loops from running away).
35
+
36
+ ## Quick start
37
+
38
+ ```bash
39
+ uv tool install proxmox-aiops
40
+ mkdir -p ~/.proxmox-aiops
41
+ # create ~/.proxmox-aiops/config.yaml with a targets: list
42
+ # put secrets in ~/.proxmox-aiops/.env (chmod 600)
43
+ proxmox-aiops doctor
44
+ ```
45
+
46
+ Example `~/.proxmox-aiops/config.yaml`:
47
+
48
+ ```yaml
49
+ targets:
50
+ - name: pve-lab
51
+ host: 10.0.0.10
52
+ user: "root@pam!claude" # API token: user@realm!tokenid
53
+ node: pve1
54
+ auth_kind: token
55
+ verify_ssl: false # self-signed lab certs only
56
+ ```
57
+
58
+ `~/.proxmox-aiops/.env` (chmod 600): `PROXMOX_PVE_LAB_SECRET=<token-uuid>`
59
+
60
+ ## Audit & safety
61
+
62
+ All operations are logged to a local SQLite audit DB under `~/.proxmox-aiops/`
63
+ (relocatable via `PROXMOX_AIOPS_HOME`). Every write tool passes through the
64
+ governance harness: policy pre-check, token/runaway budget guard, graduated
65
+ risk-tier gate, and audit logging. Destructive CLI commands (`vm stop`,
66
+ `vm delete`, `vm snapshot-delete`, `vm snapshot-rollback`, `ct stop`) require
67
+ double confirmation and support `--dry-run`. API-returned text is run through a
68
+ prompt-injection sanitizer.
69
+
70
+ License: MIT.
@@ -0,0 +1,54 @@
1
+ <!-- mcp-name: io.github.AIops-tools/proxmox-aiops -->
2
+
3
+ # Proxmox AIops (preview)
4
+
5
+ > **Disclaimer**: Community-maintained open-source project. **Not affiliated with, endorsed by, or sponsored by Proxmox Server Solutions GmbH.** "Proxmox" is a trademark of its owner. MIT licensed.
6
+
7
+ AI-powered Proxmox VE VM and container lifecycle operations with a **built-in
8
+ governance harness** — unified audit log, policy engine, token/runaway budget
9
+ guard, undo-token recording, and graduated-autonomy risk tiers. Self-contained:
10
+ no external dependencies beyond `proxmoxer` and the MCP SDK. Preview — not yet
11
+ full coverage of every Proxmox operation.
12
+
13
+ ## What works
14
+
15
+ - **CLI** (`proxmox-aiops ...`): `vm list/get/config/start/stop/shutdown/reboot/reconfigure/clone/delete/migrate`, `vm snapshot-create/snapshot-delete/snapshot-list/snapshot-rollback`, `ct list/start/stop`, `cluster nodes/status/task-status`, `storage list/content`, `doctor`, `mcp`.
16
+ - **MCP server** (`proxmox-aiops mcp` or `proxmox-aiops-mcp`): **23 tools**, every one wrapped with the bundled `@governed_tool` harness.
17
+ - **Reversibility**: write ops with a clean inverse (start/stop/shutdown/reconfigure/clone/migrate/snapshot-create, container start/stop) record an inverse undo descriptor; irreversible ops (delete, snapshot-rollback) declare none and are tagged `high` risk.
18
+ - **Async tasks**: Proxmox writes return a task UPID — poll completion with `cluster task-status` (the runaway budget guard prevents poll loops from running away).
19
+
20
+ ## Quick start
21
+
22
+ ```bash
23
+ uv tool install proxmox-aiops
24
+ mkdir -p ~/.proxmox-aiops
25
+ # create ~/.proxmox-aiops/config.yaml with a targets: list
26
+ # put secrets in ~/.proxmox-aiops/.env (chmod 600)
27
+ proxmox-aiops doctor
28
+ ```
29
+
30
+ Example `~/.proxmox-aiops/config.yaml`:
31
+
32
+ ```yaml
33
+ targets:
34
+ - name: pve-lab
35
+ host: 10.0.0.10
36
+ user: "root@pam!claude" # API token: user@realm!tokenid
37
+ node: pve1
38
+ auth_kind: token
39
+ verify_ssl: false # self-signed lab certs only
40
+ ```
41
+
42
+ `~/.proxmox-aiops/.env` (chmod 600): `PROXMOX_PVE_LAB_SECRET=<token-uuid>`
43
+
44
+ ## Audit & safety
45
+
46
+ All operations are logged to a local SQLite audit DB under `~/.proxmox-aiops/`
47
+ (relocatable via `PROXMOX_AIOPS_HOME`). Every write tool passes through the
48
+ governance harness: policy pre-check, token/runaway budget guard, graduated
49
+ risk-tier gate, and audit logging. Destructive CLI commands (`vm stop`,
50
+ `vm delete`, `vm snapshot-delete`, `vm snapshot-rollback`, `ct stop`) require
51
+ double confirmation and support `--dry-run`. API-returned text is run through a
52
+ prompt-injection sanitizer.
53
+
54
+ License: MIT.
@@ -0,0 +1,33 @@
1
+ # Release notes
2
+
3
+ ## v0.1.0 (2026-06-22) — first release (preview)
4
+
5
+ First public release of **proxmox-aiops** — governed Proxmox VE VM and container
6
+ lifecycle operations for AI agents. Standalone and self-contained.
7
+
8
+ ### Highlights
9
+ - **23 MCP tools** (8 read / 15 write):
10
+ - VM lifecycle: list/get/config, start/stop/shutdown/reboot, reconfigure,
11
+ clone, delete, migrate
12
+ - Snapshots: create/delete/list/rollback
13
+ - LXC containers: list/start/stop
14
+ - Cluster/tasks: node list, cluster status, async task (UPID) polling
15
+ - Storage: pool list, content list
16
+ - **CLI + MCP server** (`proxmox-aiops` and `proxmox-aiops mcp`).
17
+ - **Built-in governance harness** (`proxmox_aiops.governance`, no external
18
+ dependency): unified audit log under `~/.proxmox-aiops/`, policy engine,
19
+ token/runaway budget guard, undo-token recording, and graduated-autonomy
20
+ risk tiers. State dir relocatable via `PROXMOX_AIOPS_HOME`.
21
+ - **Reversibility**: write ops with a clean inverse (start/stop/shutdown/
22
+ reconfigure/clone/migrate/snapshot-create, container start/stop) record an
23
+ undo descriptor; irreversible ops (delete, snapshot-rollback) declare none
24
+ and are tagged `high` risk.
25
+ - **Safety**: destructive CLI commands require double confirmation + `--dry-run`;
26
+ all API text is sanitized; TLS verification on by default.
27
+
28
+ ### Notes
29
+ - Preview (0.x): broad coverage of common operations, not yet exhaustive — see
30
+ `references/capabilities.md` for the "not yet covered" list.
31
+ - Proxmox writes are asynchronous; poll completion with `cluster task-status`.
32
+ - Verified with a mocked Proxmox API (9 smoke tests); not yet exercised against
33
+ a live PVE cluster.
@@ -0,0 +1,63 @@
1
+ # Security Policy
2
+
3
+ ## Disclaimer
4
+
5
+ Community-maintained open-source project. **Not affiliated with, endorsed by, or
6
+ sponsored by Proxmox Server Solutions GmbH.** "Proxmox" is a trademark of its
7
+ owner. Source is publicly auditable under the MIT license.
8
+
9
+ ## Reporting Vulnerabilities
10
+
11
+ Report privately via a GitHub Security Advisory on
12
+ [github.com/AIops-tools/Proxmox-AIops](https://github.com/AIops-tools/Proxmox-AIops/security/advisories)
13
+ or email zhouwei008@gmail.com. Please do not open public issues for security
14
+ reports.
15
+
16
+ ## Security Design
17
+
18
+ ### Credential Management
19
+ - Per-target secrets live in `~/.proxmox-aiops/.env` (chmod 600), never in
20
+ `config.yaml` and never in source. Variable pattern:
21
+ `PROXMOX_<TARGET_NAME_UPPER>_SECRET` (API token UUID, or login password).
22
+ - Secrets are never logged or echoed; the config file holds only host, user,
23
+ node, and TLS settings.
24
+
25
+ ### Governed Operations
26
+ Every MCP tool runs through the bundled `@governed_tool` harness
27
+ (`proxmox_aiops.governance`):
28
+ - **Audit** — every call logged to a local SQLite DB under `~/.proxmox-aiops/`
29
+ (relocatable via `PROXMOX_AIOPS_HOME`), agent-attributed, secret-redacted.
30
+ - **Token/runaway budget** — hard ceilings (`PROXMOX_MAX_TOOL_CALLS` /
31
+ `PROXMOX_MAX_TOOL_SECONDS`) plus an on-by-default guard that trips a tight
32
+ poll/retry loop, preventing unbounded API consumption.
33
+ - **Graduated risk tiers** — `~/.proxmox-aiops/rules.yaml` `risk_tiers` gate
34
+ writes by environment/tag; the highest tiers require a recorded approver.
35
+ - **Undo-token recording** — reversible writes record an inverse descriptor so
36
+ a change can be rolled back.
37
+
38
+ ### Destructive Operations
39
+ `vm stop`, `vm delete`, `vm snapshot-delete`, `vm snapshot-rollback`, and
40
+ `ct stop` require double confirmation at the CLI layer and support `--dry-run`.
41
+
42
+ ### SSL/TLS Verification
43
+ `verify_ssl` defaults to true; disable only for self-signed lab certificates.
44
+
45
+ ### Prompt-Injection Protection
46
+ All Proxmox-API-returned text (names, UPIDs, descriptions) is passed through a
47
+ `sanitize()` truncate + control-character strip before reaching the agent.
48
+
49
+ ### Network Scope
50
+ No webhooks, no telemetry, no outbound calls beyond the configured Proxmox API
51
+ endpoint. No post-install scripts or background services.
52
+
53
+ ## Static Analysis
54
+
55
+ ```bash
56
+ uvx bandit -r proxmox_aiops/ mcp_server/
57
+ uv run ruff check .
58
+ ```
59
+
60
+ ## Supported Versions
61
+
62
+ The latest released version receives security fixes. This is a preview (0.x);
63
+ pin a version in production.
@@ -0,0 +1 @@
1
+ """MCP server package for proxmox-aiops."""
@@ -0,0 +1,102 @@
1
+ """Shared MCP server primitives: the FastMCP instance, connection helper,
2
+ error sanitisation, and the ``@tool_errors`` decorator.
3
+
4
+ Tool modules under ``mcp_server/tools/`` import ``mcp`` from here and register
5
+ their ``@mcp.tool()`` functions onto it. ``mcp_server/server.py`` then imports
6
+ those modules and runs the server.
7
+
8
+ Keep ``Optional[X]`` (never PEP 604 ``X | None``) in any FastMCP-reflected
9
+ tool signature — on older mcp/pydantic the union eval'd to ``types.UnionType``
10
+ crashes FastMCP's ``issubclass`` check (踩坑 #33).
11
+ """
12
+
13
+ import functools
14
+ import logging
15
+ import os
16
+ from collections.abc import Callable
17
+ from pathlib import Path
18
+ from typing import Any, Optional
19
+
20
+ from mcp.server.fastmcp import FastMCP
21
+
22
+ from proxmox_aiops.config import load_config
23
+ from proxmox_aiops.connection import ConnectionManager
24
+ from proxmox_aiops.governance import sanitize
25
+ from proxmox_aiops.ops.lxc import ContainerNotFoundError
26
+ from proxmox_aiops.ops.storage import NodeRequiredError
27
+ from proxmox_aiops.ops.vm_lifecycle import VMNotFoundError
28
+
29
+ logger = logging.getLogger(__name__)
30
+
31
+ _DOCTOR_HINT = "Run 'proxmox-aiops doctor' to verify connectivity and credentials."
32
+
33
+
34
+ def _safe_error(exc: Exception, tool: str) -> str:
35
+ """Return an agent-safe error string; log full detail server-side only."""
36
+ logger.error("Tool %s failed", tool, exc_info=True)
37
+ _passthrough = (
38
+ ValueError,
39
+ FileNotFoundError,
40
+ KeyError,
41
+ PermissionError,
42
+ TimeoutError,
43
+ ConnectionError,
44
+ VMNotFoundError,
45
+ NodeRequiredError,
46
+ ContainerNotFoundError,
47
+ )
48
+ if isinstance(exc, _passthrough):
49
+ return sanitize(str(exc), 300)
50
+ return f"{type(exc).__name__}: operation failed."
51
+
52
+
53
+ def tool_errors(shape: str = "dict") -> Callable:
54
+ """Wrap a tool body in the canonical try/except → ``_safe_error`` pattern.
55
+
56
+ Place this *between* ``@governed_tool`` and the function so the audit
57
+ decorator and FastMCP still see the original signature.
58
+ """
59
+
60
+ def decorator(func: Callable) -> Callable:
61
+ name = func.__name__
62
+
63
+ @functools.wraps(func)
64
+ def wrapper(*args: Any, **kwargs: Any) -> Any:
65
+ try:
66
+ return func(*args, **kwargs)
67
+ except Exception as e: # noqa: BLE001 — sanitised below
68
+ msg = _safe_error(e, name)
69
+ if shape == "list":
70
+ return [{"error": msg, "hint": _DOCTOR_HINT}]
71
+ if shape == "str":
72
+ return f"Error: {msg} {_DOCTOR_HINT}"
73
+ return {"error": msg, "hint": _DOCTOR_HINT}
74
+
75
+ return wrapper
76
+
77
+ return decorator
78
+
79
+
80
+ mcp = FastMCP(
81
+ "proxmox-aiops",
82
+ instructions=(
83
+ "Proxmox VE operations (preview): QEMU VM lifecycle (list/get/config, "
84
+ "start/stop/shutdown/reboot, reconfigure, clone, delete, migrate), "
85
+ "snapshots (create/delete/list/rollback), LXC containers (list/start/stop), "
86
+ "cluster/nodes + async task polling, and storage listing. Every tool runs "
87
+ "through the proxmox-aiops governance harness (audit / budget / risk-tier / "
88
+ "undo)."
89
+ ),
90
+ )
91
+
92
+ _conn_mgr: Optional[ConnectionManager] = None
93
+
94
+
95
+ def _get_connection(target: Optional[str] = None) -> Any:
96
+ """Return a proxmoxer connection, lazily initialising the manager."""
97
+ global _conn_mgr # noqa: PLW0603
98
+ if _conn_mgr is None:
99
+ config_path_str = os.environ.get("PROXMOX_AIOPS_CONFIG")
100
+ config_path = Path(config_path_str) if config_path_str else None
101
+ _conn_mgr = ConnectionManager(load_config(config_path))
102
+ return _conn_mgr.connect(target)
@@ -0,0 +1,28 @@
1
+ """MCP server wrapping Proxmox AIops operations (stdio transport).
2
+
3
+ Thin adapter layer: each ``@mcp.tool()`` function (in ``mcp_server/tools/``)
4
+ delegates to the ``proxmox_aiops`` ops package and is wrapped with the
5
+ proxmox-aiops ``@governed_tool`` harness (audit / budget / undo / risk-tier).
6
+
7
+ Standalone, self-governed Proxmox VE operations (preview).
8
+ For Proxmox VE only.
9
+
10
+ Source: https://github.com/AIops-tools/Proxmox-AIops
11
+ License: MIT
12
+ """
13
+
14
+ import logging
15
+
16
+ from mcp_server._shared import _safe_error, mcp, tool_errors
17
+
18
+ # Importing the tool modules registers every @mcp.tool() onto the shared
19
+ # `mcp` instance. Order does not matter; each module is self-contained.
20
+ from mcp_server.tools import cluster, lxc, storage, vm # noqa: F401 — side effects
21
+
22
+ __all__ = ["mcp", "main", "_safe_error", "tool_errors"]
23
+
24
+
25
+ def main() -> None:
26
+ """Run the MCP server over stdio."""
27
+ logging.basicConfig(level=logging.INFO)
28
+ mcp.run(transport="stdio")
@@ -0,0 +1 @@
1
+ """MCP tool modules. Importing each registers its @mcp.tool() functions."""
@@ -0,0 +1,51 @@
1
+ """Cluster / node / async-task MCP tools (all read-only)."""
2
+
3
+ from typing import Optional
4
+
5
+ from mcp_server._shared import _get_connection, mcp, tool_errors
6
+ from proxmox_aiops.governance import governed_tool
7
+ from proxmox_aiops.ops import cluster as cl
8
+
9
+
10
+ @mcp.tool()
11
+ @governed_tool(risk_level="low")
12
+ @tool_errors("list")
13
+ def node_list(target: Optional[str] = None) -> list:
14
+ """[READ] List Proxmox cluster nodes with status, cpu load, and memory.
15
+
16
+ Args:
17
+ target: Proxmox target name from config; omit to use the default.
18
+ """
19
+ return cl.list_nodes(_get_connection(target))
20
+
21
+
22
+ @mcp.tool()
23
+ @governed_tool(risk_level="low")
24
+ @tool_errors("list")
25
+ def cluster_status(target: Optional[str] = None) -> list:
26
+ """[READ] Return cluster membership + quorum status.
27
+
28
+ The ``type=cluster`` row's ``quorate`` field indicates whether the cluster
29
+ currently has quorum.
30
+
31
+ Args:
32
+ target: Proxmox target name from config.
33
+ """
34
+ return cl.cluster_status(_get_connection(target))
35
+
36
+
37
+ @mcp.tool()
38
+ @governed_tool(risk_level="low")
39
+ @tool_errors("dict")
40
+ def task_status(upid: str, target: Optional[str] = None, node: Optional[str] = None) -> dict:
41
+ """[READ] Poll a Proxmox async task (clone / migrate / backup) by its UPID.
42
+
43
+ Use after a write that returned a task UPID to check completion instead of
44
+ re-issuing the operation. The node is parsed from the UPID when omitted.
45
+
46
+ Args:
47
+ upid: The task UPID returned by an async write tool.
48
+ target: Proxmox target name from config.
49
+ node: Node the task runs on; omit to parse it from the UPID.
50
+ """
51
+ return cl.get_task_status(_get_connection(target), upid, node=node)
@@ -0,0 +1,64 @@
1
+ """LXC container MCP tools: list / start / stop (start/stop carry undo tokens)."""
2
+
3
+ from typing import Optional
4
+
5
+ from mcp_server._shared import _get_connection, mcp, tool_errors
6
+ from proxmox_aiops.governance import governed_tool
7
+ from proxmox_aiops.ops import lxc
8
+
9
+
10
+ @mcp.tool()
11
+ @governed_tool(risk_level="low")
12
+ @tool_errors("list")
13
+ def ct_list(target: Optional[str] = None, node: Optional[str] = None) -> list:
14
+ """[READ] List LXC containers with name, vmid, status, cpu, mem.
15
+
16
+ Args:
17
+ target: Proxmox target name from config; omit to use the default.
18
+ node: Node name; omit to use the configured default / all nodes.
19
+ """
20
+ return lxc.list_cts(_get_connection(target), node=node)
21
+
22
+
23
+ @mcp.tool()
24
+ @governed_tool(
25
+ risk_level="medium",
26
+ undo=lambda params, result: {
27
+ "tool": "ct_stop",
28
+ "params": {"vmid": params.get("vmid"), "node": params.get("node")},
29
+ "skill": "proxmox-aiops",
30
+ "note": "Inverse of ct_start: stop the container again.",
31
+ },
32
+ )
33
+ @tool_errors("dict")
34
+ def ct_start(vmid: int, target: Optional[str] = None, node: Optional[str] = None) -> dict:
35
+ """[WRITE] Start an LXC container. Returns the task UPID. Inverse: ct_stop.
36
+
37
+ Args:
38
+ vmid: Numeric container id (see ct_list).
39
+ target: Proxmox target name from config.
40
+ node: Node name; omit to auto-locate the container.
41
+ """
42
+ return lxc.start_ct(_get_connection(target), vmid, node=node)
43
+
44
+
45
+ @mcp.tool()
46
+ @governed_tool(
47
+ risk_level="medium",
48
+ undo=lambda params, result: {
49
+ "tool": "ct_start",
50
+ "params": {"vmid": params.get("vmid"), "node": params.get("node")},
51
+ "skill": "proxmox-aiops",
52
+ "note": "Inverse of ct_stop: start the container again.",
53
+ },
54
+ )
55
+ @tool_errors("dict")
56
+ def ct_stop(vmid: int, target: Optional[str] = None, node: Optional[str] = None) -> dict:
57
+ """[WRITE] Stop an LXC container. Returns the task UPID. Inverse: ct_start.
58
+
59
+ Args:
60
+ vmid: Numeric container id (see ct_list).
61
+ target: Proxmox target name from config.
62
+ node: Node name; omit to auto-locate the container.
63
+ """
64
+ return lxc.stop_ct(_get_connection(target), vmid, node=node)
@@ -0,0 +1,43 @@
1
+ """Storage read MCP tools for Proxmox VE."""
2
+
3
+
4
+ from typing import Optional
5
+
6
+ from mcp_server._shared import _get_connection, mcp, tool_errors
7
+ from proxmox_aiops.governance import governed_tool
8
+ from proxmox_aiops.ops import storage as st
9
+
10
+
11
+ @mcp.tool()
12
+ @governed_tool(risk_level="low")
13
+ @tool_errors("list")
14
+ def storage_list(target: Optional[str] = None, node: Optional[str] = None) -> list:
15
+ """[READ] List storage pools on a node (id, type, total/used/avail bytes).
16
+
17
+ Args:
18
+ target: Proxmox target name from config; omit to use the default.
19
+ node: Node name; omit to use the target's configured default node.
20
+ """
21
+ return st.list_storage(_get_connection(target), node=node)
22
+
23
+
24
+ @mcp.tool()
25
+ @governed_tool(risk_level="low")
26
+ @tool_errors("list")
27
+ def storage_content(
28
+ storage: str,
29
+ content: Optional[str] = None,
30
+ target: Optional[str] = None,
31
+ node: Optional[str] = None,
32
+ ) -> list:
33
+ """[READ] List volumes on a storage pool (ISOs, disk images, backups, templates).
34
+
35
+ Args:
36
+ storage: Storage pool id (see storage_list).
37
+ content: Optional filter — 'iso', 'images', 'backup', 'vztmpl'.
38
+ target: Proxmox target name from config.
39
+ node: Node name; omit to use the configured default node.
40
+ """
41
+ return st.list_storage_content(
42
+ _get_connection(target), storage, node=node, content=content
43
+ )