veeam-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 (50) hide show
  1. veeam_aiops-0.1.0/.gitignore +22 -0
  2. veeam_aiops-0.1.0/LICENSE +21 -0
  3. veeam_aiops-0.1.0/PKG-INFO +68 -0
  4. veeam_aiops-0.1.0/README.md +52 -0
  5. veeam_aiops-0.1.0/RELEASE_NOTES.md +22 -0
  6. veeam_aiops-0.1.0/SECURITY.md +68 -0
  7. veeam_aiops-0.1.0/mcp_server/__init__.py +1 -0
  8. veeam_aiops-0.1.0/mcp_server/_shared.py +96 -0
  9. veeam_aiops-0.1.0/mcp_server/server.py +34 -0
  10. veeam_aiops-0.1.0/mcp_server/tools/__init__.py +1 -0
  11. veeam_aiops-0.1.0/mcp_server/tools/backups.py +19 -0
  12. veeam_aiops-0.1.0/mcp_server/tools/jobs.py +127 -0
  13. veeam_aiops-0.1.0/mcp_server/tools/repositories.py +19 -0
  14. veeam_aiops-0.1.0/mcp_server/tools/restore.py +39 -0
  15. veeam_aiops-0.1.0/mcp_server/tools/sessions.py +35 -0
  16. veeam_aiops-0.1.0/pyproject.toml +59 -0
  17. veeam_aiops-0.1.0/server.json +21 -0
  18. veeam_aiops-0.1.0/skills/veeam-aiops/SKILL.md +158 -0
  19. veeam_aiops-0.1.0/skills/veeam-aiops/references/capabilities.md +67 -0
  20. veeam_aiops-0.1.0/skills/veeam-aiops/references/cli-reference.md +56 -0
  21. veeam_aiops-0.1.0/skills/veeam-aiops/references/setup-guide.md +77 -0
  22. veeam_aiops-0.1.0/tests/test_smoke.py +227 -0
  23. veeam_aiops-0.1.0/veeam_aiops/__init__.py +9 -0
  24. veeam_aiops-0.1.0/veeam_aiops/cli/__init__.py +9 -0
  25. veeam_aiops-0.1.0/veeam_aiops/cli/_common.py +78 -0
  26. veeam_aiops-0.1.0/veeam_aiops/cli/_root.py +56 -0
  27. veeam_aiops-0.1.0/veeam_aiops/cli/backup.py +27 -0
  28. veeam_aiops-0.1.0/veeam_aiops/cli/doctor.py +21 -0
  29. veeam_aiops-0.1.0/veeam_aiops/cli/job.py +85 -0
  30. veeam_aiops-0.1.0/veeam_aiops/cli/repository.py +27 -0
  31. veeam_aiops-0.1.0/veeam_aiops/cli/restore.py +55 -0
  32. veeam_aiops-0.1.0/veeam_aiops/cli/session.py +37 -0
  33. veeam_aiops-0.1.0/veeam_aiops/config.py +131 -0
  34. veeam_aiops-0.1.0/veeam_aiops/connection.py +195 -0
  35. veeam_aiops-0.1.0/veeam_aiops/doctor.py +65 -0
  36. veeam_aiops-0.1.0/veeam_aiops/governance/__init__.py +40 -0
  37. veeam_aiops-0.1.0/veeam_aiops/governance/audit.py +377 -0
  38. veeam_aiops-0.1.0/veeam_aiops/governance/budget.py +225 -0
  39. veeam_aiops-0.1.0/veeam_aiops/governance/decorators.py +474 -0
  40. veeam_aiops-0.1.0/veeam_aiops/governance/paths.py +23 -0
  41. veeam_aiops-0.1.0/veeam_aiops/governance/patterns.py +378 -0
  42. veeam_aiops-0.1.0/veeam_aiops/governance/policy.py +411 -0
  43. veeam_aiops-0.1.0/veeam_aiops/governance/sanitize.py +39 -0
  44. veeam_aiops-0.1.0/veeam_aiops/governance/undo.py +218 -0
  45. veeam_aiops-0.1.0/veeam_aiops/ops/__init__.py +1 -0
  46. veeam_aiops-0.1.0/veeam_aiops/ops/backups.py +24 -0
  47. veeam_aiops-0.1.0/veeam_aiops/ops/jobs.py +63 -0
  48. veeam_aiops-0.1.0/veeam_aiops/ops/repositories.py +24 -0
  49. veeam_aiops-0.1.0/veeam_aiops/ops/restore.py +49 -0
  50. veeam_aiops-0.1.0/veeam_aiops/ops/sessions.py +44 -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,68 @@
1
+ Metadata-Version: 2.4
2
+ Name: veeam-aiops
3
+ Version: 0.1.0
4
+ Summary: Veeam Backup & Replication AI-powered backup 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: httpx<1.0,>=0.27
10
+ Requires-Dist: mcp[cli]<2.0,>=1.10
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/veeam-aiops -->
18
+
19
+ # Veeam AIops (preview)
20
+
21
+ > **Disclaimer**: Community-maintained open-source project. **Not affiliated with, endorsed by, or sponsored by Veeam Software.** "Veeam" is a trademark of its owner. MIT licensed.
22
+
23
+ AI-powered Veeam Backup & Replication operations with a **built-in governance
24
+ harness** — unified audit log, policy engine, token/runaway budget guard,
25
+ undo-token recording, and graduated-autonomy risk tiers. Self-contained: no
26
+ external dependencies beyond `httpx` and the MCP SDK. Preview — not yet full
27
+ coverage of every Veeam operation.
28
+
29
+ ## What works
30
+
31
+ - **CLI** (`veeam-aiops ...`): `job list/get/start/stop/enable/disable`, `restore list-points/start`, `repository list`, `session list/get`, `backup list`, `doctor`, `mcp`.
32
+ - **MCP server** (`veeam-aiops mcp` or `veeam-aiops-mcp`): **12 tools** (8 read, 4 write), every one wrapped with the bundled `@governed_tool` harness.
33
+ - **Reversibility**: write ops with a clean inverse (job start/stop, enable/disable) record an inverse undo descriptor; the irreversible VM restore declares none and is tagged `high` risk.
34
+ - **Async sessions**: Veeam jobs and restores run as sessions — poll progress with `session list` / `session get` (the runaway budget guard prevents poll loops from running away).
35
+
36
+ ## Quick start
37
+
38
+ ```bash
39
+ uv tool install veeam-aiops
40
+ mkdir -p ~/.veeam-aiops
41
+ # create ~/.veeam-aiops/config.yaml with a targets: list
42
+ # put passwords in ~/.veeam-aiops/.env (chmod 600)
43
+ veeam-aiops doctor
44
+ ```
45
+
46
+ Example `~/.veeam-aiops/config.yaml`:
47
+
48
+ ```yaml
49
+ targets:
50
+ - name: vbr-lab
51
+ host: 10.0.0.20
52
+ username: "DOMAIN\\backup-admin"
53
+ port: 9419
54
+ verify_ssl: false # self-signed lab certs only
55
+ ```
56
+
57
+ `~/.veeam-aiops/.env` (chmod 600): `VEEAM_VBR_LAB_PASSWORD=<password>`
58
+
59
+ ## Audit & safety
60
+
61
+ All operations are logged to a local SQLite audit DB under `~/.veeam-aiops/`
62
+ (relocatable via `VEEAM_AIOPS_HOME`). Every write tool passes through the
63
+ governance harness: policy pre-check, token/runaway budget guard, graduated
64
+ risk-tier gate, and audit logging. Destructive CLI commands (`job stop`,
65
+ `restore start`) require double confirmation and support `--dry-run`.
66
+ API-returned text is run through a prompt-injection sanitizer.
67
+
68
+ License: MIT.
@@ -0,0 +1,52 @@
1
+ <!-- mcp-name: io.github.AIops-tools/veeam-aiops -->
2
+
3
+ # Veeam AIops (preview)
4
+
5
+ > **Disclaimer**: Community-maintained open-source project. **Not affiliated with, endorsed by, or sponsored by Veeam Software.** "Veeam" is a trademark of its owner. MIT licensed.
6
+
7
+ AI-powered Veeam Backup & Replication operations with a **built-in governance
8
+ harness** — unified audit log, policy engine, token/runaway budget guard,
9
+ undo-token recording, and graduated-autonomy risk tiers. Self-contained: no
10
+ external dependencies beyond `httpx` and the MCP SDK. Preview — not yet full
11
+ coverage of every Veeam operation.
12
+
13
+ ## What works
14
+
15
+ - **CLI** (`veeam-aiops ...`): `job list/get/start/stop/enable/disable`, `restore list-points/start`, `repository list`, `session list/get`, `backup list`, `doctor`, `mcp`.
16
+ - **MCP server** (`veeam-aiops mcp` or `veeam-aiops-mcp`): **12 tools** (8 read, 4 write), every one wrapped with the bundled `@governed_tool` harness.
17
+ - **Reversibility**: write ops with a clean inverse (job start/stop, enable/disable) record an inverse undo descriptor; the irreversible VM restore declares none and is tagged `high` risk.
18
+ - **Async sessions**: Veeam jobs and restores run as sessions — poll progress with `session list` / `session get` (the runaway budget guard prevents poll loops from running away).
19
+
20
+ ## Quick start
21
+
22
+ ```bash
23
+ uv tool install veeam-aiops
24
+ mkdir -p ~/.veeam-aiops
25
+ # create ~/.veeam-aiops/config.yaml with a targets: list
26
+ # put passwords in ~/.veeam-aiops/.env (chmod 600)
27
+ veeam-aiops doctor
28
+ ```
29
+
30
+ Example `~/.veeam-aiops/config.yaml`:
31
+
32
+ ```yaml
33
+ targets:
34
+ - name: vbr-lab
35
+ host: 10.0.0.20
36
+ username: "DOMAIN\\backup-admin"
37
+ port: 9419
38
+ verify_ssl: false # self-signed lab certs only
39
+ ```
40
+
41
+ `~/.veeam-aiops/.env` (chmod 600): `VEEAM_VBR_LAB_PASSWORD=<password>`
42
+
43
+ ## Audit & safety
44
+
45
+ All operations are logged to a local SQLite audit DB under `~/.veeam-aiops/`
46
+ (relocatable via `VEEAM_AIOPS_HOME`). Every write tool passes through the
47
+ governance harness: policy pre-check, token/runaway budget guard, graduated
48
+ risk-tier gate, and audit logging. Destructive CLI commands (`job stop`,
49
+ `restore start`) require double confirmation and support `--dry-run`.
50
+ API-returned text is run through a prompt-injection sanitizer.
51
+
52
+ License: MIT.
@@ -0,0 +1,22 @@
1
+ # Release Notes
2
+
3
+ ## 0.1.0 (preview)
4
+
5
+ Initial preview release of **veeam-aiops** — governed Veeam Backup & Replication
6
+ operations for AI agents.
7
+
8
+ - **12 MCP tools** (8 read, 4 write), every one wrapped with the bundled
9
+ `@governed_tool` governance harness (audit, policy, token/runaway budget,
10
+ undo-token recording, graduated risk tiers).
11
+ - **Backup jobs**: list, get, start, stop, enable, disable.
12
+ - **Restore**: list restore points, start a VM restore (high-risk skeleton).
13
+ - **Repositories** and **stored backups**: list.
14
+ - **Sessions**: list and get, for polling async job/restore progress.
15
+ - **CLI** (`veeam-aiops ...`) with `--dry-run` and double-confirm on destructive
16
+ ops, plus `doctor` and an `mcp` stdio subcommand.
17
+ - Veeam VBR REST API connection layer (OAuth2 password grant → bearer token,
18
+ `x-api-version: 1.1-rev1`, central HTTP-error translation into
19
+ `VeeamApiError` teaching messages).
20
+ - Self-contained: bundled governance harness, no external skill-family
21
+ dependency. Dependencies: `httpx`, `typer`, `rich`, `pyyaml`,
22
+ `python-dotenv`, `mcp[cli]`.
@@ -0,0 +1,68 @@
1
+ # Security Policy
2
+
3
+ ## Disclaimer
4
+
5
+ Community-maintained open-source project. **Not affiliated with, endorsed by, or
6
+ sponsored by Veeam Software.** "Veeam" is a trademark of its owner. Source is
7
+ 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/Veeam-AIops](https://github.com/AIops-tools/Veeam-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 passwords live in `~/.veeam-aiops/.env` (chmod 600), never in
20
+ `config.yaml` and never in source. Variable pattern:
21
+ `VEEAM_<TARGET_NAME_UPPER>_PASSWORD`.
22
+ - Passwords are exchanged for a short-lived OAuth2 bearer token at connect time;
23
+ the token is held only in memory (side-stored by connection id, never set as
24
+ an attribute on the HTTP client). Secrets are never logged or echoed; the
25
+ config file holds only host, port, username, and TLS settings.
26
+
27
+ ### Governed Operations
28
+ Every MCP tool runs through the bundled `@governed_tool` harness
29
+ (`veeam_aiops.governance`):
30
+ - **Audit** — every call logged to a local SQLite DB under `~/.veeam-aiops/`
31
+ (relocatable via `VEEAM_AIOPS_HOME`), agent-attributed, secret-redacted.
32
+ - **Token/runaway budget** — hard ceilings (`VEEAM_MAX_TOOL_CALLS` /
33
+ `VEEAM_MAX_TOOL_SECONDS`) plus an on-by-default guard that trips a tight
34
+ poll/retry loop, preventing unbounded API consumption (e.g. polling a slow
35
+ session).
36
+ - **Graduated risk tiers** — `~/.veeam-aiops/rules.yaml` `risk_tiers` gate
37
+ writes by environment/tag; the highest tiers require a recorded approver.
38
+ - **Undo-token recording** — reversible writes (job start/stop, enable/disable)
39
+ record an inverse descriptor so a change can be rolled back.
40
+
41
+ ### Destructive Operations
42
+ `job stop` and `restore start` require double confirmation at the CLI layer and
43
+ support `--dry-run`. The VM restore is irreversible (overwrites/creates a VM),
44
+ tagged `risk_level=high`, and records no undo token.
45
+
46
+ ### SSL/TLS Verification
47
+ `verify_ssl` defaults to true; disable only for self-signed lab certificates.
48
+
49
+ ### Prompt-Injection Protection
50
+ All Veeam-API-returned text (job names, session results, descriptions) is passed
51
+ through a `sanitize()` truncate + control-character strip before reaching the
52
+ agent.
53
+
54
+ ### Network Scope
55
+ No webhooks, no telemetry, no outbound calls beyond the configured Veeam B&R
56
+ REST API endpoint. No post-install scripts or background services.
57
+
58
+ ## Static Analysis
59
+
60
+ ```bash
61
+ uvx bandit -r veeam_aiops/ mcp_server/
62
+ uv run ruff check .
63
+ ```
64
+
65
+ ## Supported Versions
66
+
67
+ The latest released version receives security fixes. This is a preview (0.x);
68
+ pin a version in production.
@@ -0,0 +1 @@
1
+ """MCP server package for veeam-aiops."""
@@ -0,0 +1,96 @@
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.
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 veeam_aiops.config import load_config
23
+ from veeam_aiops.connection import ConnectionManager, VeeamApiError
24
+ from veeam_aiops.governance import sanitize
25
+
26
+ logger = logging.getLogger(__name__)
27
+
28
+ _DOCTOR_HINT = "Run 'veeam-aiops doctor' to verify connectivity and credentials."
29
+
30
+
31
+ def _safe_error(exc: Exception, tool: str) -> str:
32
+ """Return an agent-safe error string; log full detail server-side only."""
33
+ logger.error("Tool %s failed", tool, exc_info=True)
34
+ _passthrough = (
35
+ ValueError,
36
+ FileNotFoundError,
37
+ KeyError,
38
+ PermissionError,
39
+ TimeoutError,
40
+ ConnectionError,
41
+ VeeamApiError,
42
+ )
43
+ if isinstance(exc, _passthrough):
44
+ return sanitize(str(exc), 300)
45
+ return f"{type(exc).__name__}: operation failed."
46
+
47
+
48
+ def tool_errors(shape: str = "dict") -> Callable:
49
+ """Wrap a tool body in the canonical try/except → ``_safe_error`` pattern.
50
+
51
+ Place this *between* ``@governed_tool`` and the function so the audit
52
+ decorator and FastMCP still see the original signature.
53
+ """
54
+
55
+ def decorator(func: Callable) -> Callable:
56
+ name = func.__name__
57
+
58
+ @functools.wraps(func)
59
+ def wrapper(*args: Any, **kwargs: Any) -> Any:
60
+ try:
61
+ return func(*args, **kwargs)
62
+ except Exception as e: # noqa: BLE001 — sanitised below
63
+ msg = _safe_error(e, name)
64
+ if shape == "list":
65
+ return [{"error": msg, "hint": _DOCTOR_HINT}]
66
+ if shape == "str":
67
+ return f"Error: {msg} {_DOCTOR_HINT}"
68
+ return {"error": msg, "hint": _DOCTOR_HINT}
69
+
70
+ return wrapper
71
+
72
+ return decorator
73
+
74
+
75
+ mcp = FastMCP(
76
+ "veeam-aiops",
77
+ instructions=(
78
+ "Veeam Backup & Replication operations (preview): backup jobs "
79
+ "(list/get, start/stop, enable/disable), restore points + VM restore, "
80
+ "backup repositories, stored backups, and async sessions for polling "
81
+ "job/restore progress. Every tool runs through the veeam-aiops governance "
82
+ "harness (audit / budget / risk-tier / undo)."
83
+ ),
84
+ )
85
+
86
+ _conn_mgr: Optional[ConnectionManager] = None
87
+
88
+
89
+ def _get_connection(target: Optional[str] = None) -> Any:
90
+ """Return a Veeam connection, lazily initialising the manager."""
91
+ global _conn_mgr # noqa: PLW0603
92
+ if _conn_mgr is None:
93
+ config_path_str = os.environ.get("VEEAM_AIOPS_CONFIG")
94
+ config_path = Path(config_path_str) if config_path_str else None
95
+ _conn_mgr = ConnectionManager(load_config(config_path))
96
+ return _conn_mgr.connect(target)
@@ -0,0 +1,34 @@
1
+ """MCP server wrapping Veeam AIops operations (stdio transport).
2
+
3
+ Thin adapter layer: each ``@mcp.tool()`` function (in ``mcp_server/tools/``)
4
+ delegates to the ``veeam_aiops`` ops package and is wrapped with the
5
+ veeam-aiops ``@governed_tool`` harness (audit / budget / undo / risk-tier).
6
+
7
+ Standalone, self-governed Veeam Backup & Replication operations (preview).
8
+ For Veeam Backup & Replication only.
9
+
10
+ Source: https://github.com/AIops-tools/Veeam-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 ( # noqa: F401 — side effects
21
+ backups,
22
+ jobs,
23
+ repositories,
24
+ restore,
25
+ sessions,
26
+ )
27
+
28
+ __all__ = ["mcp", "main", "_safe_error", "tool_errors"]
29
+
30
+
31
+ def main() -> None:
32
+ """Run the MCP server over stdio."""
33
+ logging.basicConfig(level=logging.INFO)
34
+ mcp.run(transport="stdio")
@@ -0,0 +1 @@
1
+ """MCP tool modules. Importing each registers its @mcp.tool() functions."""
@@ -0,0 +1,19 @@
1
+ """Stored-backup MCP tools (read-only)."""
2
+
3
+ from typing import Optional
4
+
5
+ from mcp_server._shared import _get_connection, mcp, tool_errors
6
+ from veeam_aiops.governance import governed_tool
7
+ from veeam_aiops.ops import backups as ops
8
+
9
+
10
+ @mcp.tool()
11
+ @governed_tool(risk_level="low")
12
+ @tool_errors("list")
13
+ def backup_list(target: Optional[str] = None) -> list:
14
+ """[READ] List stored backups with id, name, type, creationTime.
15
+
16
+ Args:
17
+ target: Veeam target name from config; omit to use the default.
18
+ """
19
+ return ops.list_backups(_get_connection(target))
@@ -0,0 +1,127 @@
1
+ """Backup job MCP tools: list/get, start/stop, enable/disable.
2
+
3
+ Every tool is wrapped with ``@governed_tool`` (the veeam-aiops harness):
4
+ policy pre-check, budget/runaway guard, graduated-autonomy risk-tier gate,
5
+ audit logging to ~/.veeam-aiops/audit.db, and undo-token recording. Write tools
6
+ with a clean inverse pass an ``undo=`` lambda so the harness records a reversal
7
+ descriptor to the undo store (start↔stop, enable↔disable).
8
+ """
9
+
10
+ from typing import Optional
11
+
12
+ from mcp_server._shared import _get_connection, mcp, tool_errors
13
+ from veeam_aiops.governance import governed_tool
14
+ from veeam_aiops.ops import jobs as ops
15
+
16
+
17
+ @mcp.tool()
18
+ @governed_tool(risk_level="low")
19
+ @tool_errors("list")
20
+ def job_list(target: Optional[str] = None) -> list:
21
+ """[READ] List backup jobs with id, name, type, status, lastResult.
22
+
23
+ Use job_get for full detail of a single job.
24
+
25
+ Args:
26
+ target: Veeam target name from config; omit to use the default.
27
+ """
28
+ return ops.list_jobs(_get_connection(target))
29
+
30
+
31
+ @mcp.tool()
32
+ @governed_tool(risk_level="low")
33
+ @tool_errors("dict")
34
+ def job_get(job_id: str, target: Optional[str] = None) -> dict:
35
+ """[READ] Return detail for a single backup job by id.
36
+
37
+ Args:
38
+ job_id: Veeam job id (see job_list).
39
+ target: Veeam target name from config.
40
+ """
41
+ return ops.get_job(_get_connection(target), job_id)
42
+
43
+
44
+ @mcp.tool()
45
+ @governed_tool(
46
+ risk_level="medium",
47
+ undo=lambda params, result: {
48
+ "tool": "job_stop",
49
+ "params": {"job_id": params.get("job_id")},
50
+ "skill": "veeam-aiops",
51
+ "note": "Inverse of job_start: stop the running job.",
52
+ },
53
+ )
54
+ @tool_errors("dict")
55
+ def job_start(job_id: str, target: Optional[str] = None) -> dict:
56
+ """[WRITE] Start a backup job. Runs as an async session. Inverse: job_stop.
57
+
58
+ Poll progress with session_list / session_get; do not re-issue.
59
+
60
+ Args:
61
+ job_id: Veeam job id.
62
+ target: Veeam target name from config.
63
+ """
64
+ return ops.start_job(_get_connection(target), job_id)
65
+
66
+
67
+ @mcp.tool()
68
+ @governed_tool(
69
+ risk_level="medium",
70
+ undo=lambda params, result: {
71
+ "tool": "job_start",
72
+ "params": {"job_id": params.get("job_id")},
73
+ "skill": "veeam-aiops",
74
+ "note": "Inverse of job_stop: start the job again.",
75
+ },
76
+ )
77
+ @tool_errors("dict")
78
+ def job_stop(job_id: str, target: Optional[str] = None) -> dict:
79
+ """[WRITE] Stop a running backup job. Inverse: job_start.
80
+
81
+ Args:
82
+ job_id: Veeam job id.
83
+ target: Veeam target name from config.
84
+ """
85
+ return ops.stop_job(_get_connection(target), job_id)
86
+
87
+
88
+ @mcp.tool()
89
+ @governed_tool(
90
+ risk_level="medium",
91
+ undo=lambda params, result: {
92
+ "tool": "job_disable",
93
+ "params": {"job_id": params.get("job_id")},
94
+ "skill": "veeam-aiops",
95
+ "note": "Inverse of job_enable: disable the job again.",
96
+ },
97
+ )
98
+ @tool_errors("dict")
99
+ def job_enable(job_id: str, target: Optional[str] = None) -> dict:
100
+ """[WRITE] Enable a backup job (clears the disabled flag). Inverse: job_disable.
101
+
102
+ Args:
103
+ job_id: Veeam job id.
104
+ target: Veeam target name from config.
105
+ """
106
+ return ops.enable_job(_get_connection(target), job_id)
107
+
108
+
109
+ @mcp.tool()
110
+ @governed_tool(
111
+ risk_level="medium",
112
+ undo=lambda params, result: {
113
+ "tool": "job_enable",
114
+ "params": {"job_id": params.get("job_id")},
115
+ "skill": "veeam-aiops",
116
+ "note": "Inverse of job_disable: enable the job again.",
117
+ },
118
+ )
119
+ @tool_errors("dict")
120
+ def job_disable(job_id: str, target: Optional[str] = None) -> dict:
121
+ """[WRITE] Disable a backup job (skips scheduled runs). Inverse: job_enable.
122
+
123
+ Args:
124
+ job_id: Veeam job id.
125
+ target: Veeam target name from config.
126
+ """
127
+ return ops.disable_job(_get_connection(target), job_id)
@@ -0,0 +1,19 @@
1
+ """Backup repository MCP tools (read-only)."""
2
+
3
+ from typing import Optional
4
+
5
+ from mcp_server._shared import _get_connection, mcp, tool_errors
6
+ from veeam_aiops.governance import governed_tool
7
+ from veeam_aiops.ops import repositories as ops
8
+
9
+
10
+ @mcp.tool()
11
+ @governed_tool(risk_level="low")
12
+ @tool_errors("list")
13
+ def repository_list(target: Optional[str] = None) -> list:
14
+ """[READ] List backup repositories with id, name, type, path.
15
+
16
+ Args:
17
+ target: Veeam target name from config; omit to use the default.
18
+ """
19
+ return ops.list_repositories(_get_connection(target))
@@ -0,0 +1,39 @@
1
+ """Restore MCP tools: list restore points, start a VM restore.
2
+
3
+ start_vm_restore is high-risk with NO undo token — restoring a VM overwrites
4
+ or creates one and cannot be reversed by the harness.
5
+ """
6
+
7
+ from typing import Optional
8
+
9
+ from mcp_server._shared import _get_connection, mcp, tool_errors
10
+ from veeam_aiops.governance import governed_tool
11
+ from veeam_aiops.ops import restore as ops
12
+
13
+
14
+ @mcp.tool()
15
+ @governed_tool(risk_level="low")
16
+ @tool_errors("list")
17
+ def restore_list_points(target: Optional[str] = None) -> list:
18
+ """[READ] List available restore points (id, name, creationTime, type).
19
+
20
+ Args:
21
+ target: Veeam target name from config; omit to use the default.
22
+ """
23
+ return ops.list_restore_points(_get_connection(target))
24
+
25
+
26
+ @mcp.tool()
27
+ @governed_tool(risk_level="high")
28
+ @tool_errors("dict")
29
+ def start_vm_restore(restore_point_id: str, target: Optional[str] = None) -> dict:
30
+ """[WRITE] Start a VM restore from a restore point. IRREVERSIBLE — no undo token.
31
+
32
+ Overwrites or creates a VM; confirm with the user before calling. Runs as an
33
+ async session — poll with session_list / session_get.
34
+
35
+ Args:
36
+ restore_point_id: Restore point id (see restore_list_points).
37
+ target: Veeam target name from config.
38
+ """
39
+ return ops.start_vm_restore(_get_connection(target), restore_point_id)
@@ -0,0 +1,35 @@
1
+ """Session MCP tools (read-only): poll async job/restore progress."""
2
+
3
+ from typing import Optional
4
+
5
+ from mcp_server._shared import _get_connection, mcp, tool_errors
6
+ from veeam_aiops.governance import governed_tool
7
+ from veeam_aiops.ops import sessions as ops
8
+
9
+
10
+ @mcp.tool()
11
+ @governed_tool(risk_level="low")
12
+ @tool_errors("list")
13
+ def session_list(target: Optional[str] = None) -> list:
14
+ """[READ] List recent sessions with id, name, type, state, result.
15
+
16
+ Args:
17
+ target: Veeam target name from config; omit to use the default.
18
+ """
19
+ return ops.list_sessions(_get_connection(target))
20
+
21
+
22
+ @mcp.tool()
23
+ @governed_tool(risk_level="low")
24
+ @tool_errors("dict")
25
+ def session_get(session_id: str, target: Optional[str] = None) -> dict:
26
+ """[READ] Poll one session by id to check job/restore progress.
27
+
28
+ Use after job_start or start_vm_restore to follow the operation instead of
29
+ re-issuing it.
30
+
31
+ Args:
32
+ session_id: Veeam session id (see session_list).
33
+ target: Veeam target name from config.
34
+ """
35
+ return ops.get_session(_get_connection(target), session_id)