nutanix-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.
- nutanix_aiops-0.1.0/.gitignore +7 -0
- nutanix_aiops-0.1.0/CHANGELOG.md +61 -0
- nutanix_aiops-0.1.0/LICENSE +21 -0
- nutanix_aiops-0.1.0/PKG-INFO +136 -0
- nutanix_aiops-0.1.0/README.md +120 -0
- nutanix_aiops-0.1.0/RELEASE_NOTES.md +58 -0
- nutanix_aiops-0.1.0/SECURITY.md +81 -0
- nutanix_aiops-0.1.0/mcp_server/__init__.py +1 -0
- nutanix_aiops-0.1.0/mcp_server/_shared.py +100 -0
- nutanix_aiops-0.1.0/mcp_server/server.py +39 -0
- nutanix_aiops-0.1.0/mcp_server/tools/__init__.py +1 -0
- nutanix_aiops-0.1.0/mcp_server/tools/alerts.py +97 -0
- nutanix_aiops-0.1.0/mcp_server/tools/capacity.py +49 -0
- nutanix_aiops-0.1.0/mcp_server/tools/catalog.py +102 -0
- nutanix_aiops-0.1.0/mcp_server/tools/clusters.py +59 -0
- nutanix_aiops-0.1.0/mcp_server/tools/dataprotection.py +177 -0
- nutanix_aiops-0.1.0/mcp_server/tools/lcm.py +69 -0
- nutanix_aiops-0.1.0/mcp_server/tools/network.py +87 -0
- nutanix_aiops-0.1.0/mcp_server/tools/storage.py +120 -0
- nutanix_aiops-0.1.0/mcp_server/tools/vms.py +250 -0
- nutanix_aiops-0.1.0/nutanix_aiops/__init__.py +9 -0
- nutanix_aiops-0.1.0/nutanix_aiops/cli/__init__.py +9 -0
- nutanix_aiops-0.1.0/nutanix_aiops/cli/_common.py +78 -0
- nutanix_aiops-0.1.0/nutanix_aiops/cli/_root.py +57 -0
- nutanix_aiops-0.1.0/nutanix_aiops/cli/cluster.py +58 -0
- nutanix_aiops-0.1.0/nutanix_aiops/cli/doctor.py +21 -0
- nutanix_aiops-0.1.0/nutanix_aiops/cli/init.py +102 -0
- nutanix_aiops-0.1.0/nutanix_aiops/cli/overview.py +16 -0
- nutanix_aiops-0.1.0/nutanix_aiops/cli/secret.py +103 -0
- nutanix_aiops-0.1.0/nutanix_aiops/cli/vm.py +112 -0
- nutanix_aiops-0.1.0/nutanix_aiops/config.py +141 -0
- nutanix_aiops-0.1.0/nutanix_aiops/connection.py +247 -0
- nutanix_aiops-0.1.0/nutanix_aiops/doctor.py +86 -0
- nutanix_aiops-0.1.0/nutanix_aiops/governance/__init__.py +40 -0
- nutanix_aiops-0.1.0/nutanix_aiops/governance/audit.py +377 -0
- nutanix_aiops-0.1.0/nutanix_aiops/governance/budget.py +225 -0
- nutanix_aiops-0.1.0/nutanix_aiops/governance/decorators.py +474 -0
- nutanix_aiops-0.1.0/nutanix_aiops/governance/paths.py +23 -0
- nutanix_aiops-0.1.0/nutanix_aiops/governance/patterns.py +378 -0
- nutanix_aiops-0.1.0/nutanix_aiops/governance/policy.py +411 -0
- nutanix_aiops-0.1.0/nutanix_aiops/governance/sanitize.py +39 -0
- nutanix_aiops-0.1.0/nutanix_aiops/governance/undo.py +218 -0
- nutanix_aiops-0.1.0/nutanix_aiops/ops/__init__.py +1 -0
- nutanix_aiops-0.1.0/nutanix_aiops/ops/_util.py +42 -0
- nutanix_aiops-0.1.0/nutanix_aiops/ops/alerts.py +159 -0
- nutanix_aiops-0.1.0/nutanix_aiops/ops/capacity.py +88 -0
- nutanix_aiops-0.1.0/nutanix_aiops/ops/catalog.py +88 -0
- nutanix_aiops-0.1.0/nutanix_aiops/ops/clusters.py +94 -0
- nutanix_aiops-0.1.0/nutanix_aiops/ops/dataprotection.py +122 -0
- nutanix_aiops-0.1.0/nutanix_aiops/ops/lcm.py +73 -0
- nutanix_aiops-0.1.0/nutanix_aiops/ops/network.py +103 -0
- nutanix_aiops-0.1.0/nutanix_aiops/ops/overview.py +47 -0
- nutanix_aiops-0.1.0/nutanix_aiops/ops/storage.py +105 -0
- nutanix_aiops-0.1.0/nutanix_aiops/ops/vms.py +184 -0
- nutanix_aiops-0.1.0/nutanix_aiops/secretstore.py +302 -0
- nutanix_aiops-0.1.0/pyproject.toml +59 -0
- nutanix_aiops-0.1.0/server.json +21 -0
- nutanix_aiops-0.1.0/skills/nutanix-aiops/SKILL.md +117 -0
- nutanix_aiops-0.1.0/skills/nutanix-aiops/references/capabilities.md +120 -0
- nutanix_aiops-0.1.0/skills/nutanix-aiops/references/cli-reference.md +64 -0
- nutanix_aiops-0.1.0/skills/nutanix-aiops/references/setup-guide.md +104 -0
- nutanix_aiops-0.1.0/smithery.yaml +9 -0
- nutanix_aiops-0.1.0/tests/test_alerts.py +87 -0
- nutanix_aiops-0.1.0/tests/test_capacity.py +75 -0
- nutanix_aiops-0.1.0/tests/test_catalog.py +71 -0
- nutanix_aiops-0.1.0/tests/test_dataprotection.py +69 -0
- nutanix_aiops-0.1.0/tests/test_lcm.py +69 -0
- nutanix_aiops-0.1.0/tests/test_network.py +89 -0
- nutanix_aiops-0.1.0/tests/test_secretstore.py +99 -0
- nutanix_aiops-0.1.0/tests/test_smoke.py +312 -0
- nutanix_aiops-0.1.0/tests/test_storage.py +75 -0
- nutanix_aiops-0.1.0/uv.lock +962 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to nutanix-aiops are documented here. This project adheres
|
|
4
|
+
to [Semantic Versioning](https://semver.org/).
|
|
5
|
+
|
|
6
|
+
## [0.1.0] — preview
|
|
7
|
+
|
|
8
|
+
Initial preview release: governed AI-ops for **Nutanix Prism Central** (v4 REST
|
|
9
|
+
API) with a bundled governance harness. **Mock-validated only — not yet verified
|
|
10
|
+
against a live Prism Central.**
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **47 MCP tools** (21 read, 26 write), every one wrapped with the bundled
|
|
15
|
+
`@governed_tool` harness (audit, policy, token/runaway budget, undo,
|
|
16
|
+
risk-tiers):
|
|
17
|
+
- **Clusters** (read) — `cluster_list`, `cluster_health`, `host_list`,
|
|
18
|
+
`cluster_utilization`.
|
|
19
|
+
- **VMs** — `vm_list` (AHV + ESXi), `vm_get` (surfaces ETag); `vm_power_on`
|
|
20
|
+
(low), `vm_guest_shutdown` / `vm_power_off` / `vm_reboot` / `vm_create` /
|
|
21
|
+
`vm_update` (med, undo prior CPU/mem) / `vm_clone` (med); `vm_delete` and
|
|
22
|
+
`vm_migrate` (HIGH, dry-run; `vm_migrate` undo → prior host).
|
|
23
|
+
- **Storage** — `storage_container_list`; `storage_container_create` /
|
|
24
|
+
`_update` (med, undo prior); `storage_container_delete` (HIGH, dry-run).
|
|
25
|
+
- **Network** — `subnet_list`, `subnet_get` (ETag); `subnet_create` (med);
|
|
26
|
+
`subnet_delete` (HIGH, dry-run).
|
|
27
|
+
- **Catalog** — `image_list`; `image_delete` (HIGH, dry-run); `category_list`;
|
|
28
|
+
`category_create` (low); `category_assign` (med, bulk-assign to VMs).
|
|
29
|
+
- **Data protection / DR** — `snapshot_list`, `recovery_point_list`,
|
|
30
|
+
`protection_domain_list`; `snapshot_create` (low); `vm_protect` (med);
|
|
31
|
+
`snapshot_delete` / `snapshot_restore` / `pd_failover` (HIGH, dry-run).
|
|
32
|
+
- **Alerts** — `alert_list`, `event_list`, `audit_list`; `analyze_alert`
|
|
33
|
+
(RCA — correlates an alert with related events into a probable-cause +
|
|
34
|
+
suggested-actions summary); `alert_acknowledge` / `alert_resolve` (low).
|
|
35
|
+
- **LCM** — `lcm_inventory`; `lcm_precheck` (low); `lcm_update` (HIGH
|
|
36
|
+
firmware/software update, dry-run).
|
|
37
|
+
- **Capacity** — `task_list`; `capacity_runway` (days-to-full forecast).
|
|
38
|
+
- **Automatic ETag / If-Match** handling on every mutation and **automatic
|
|
39
|
+
pagination** on every list tool.
|
|
40
|
+
- **Mixed-hypervisor VM listing** — `vm_list` returns both AHV and ESXi guests.
|
|
41
|
+
- **Encrypted secret store** — the Prism Central password is stored encrypted in
|
|
42
|
+
`~/.nutanix-aiops/secrets.enc` (Fernet + scrypt); never plaintext on disk.
|
|
43
|
+
Legacy `NUTANIX_<TARGET>_PASSWORD` env var honoured as a fallback.
|
|
44
|
+
- **CLI** (`nutanix-aiops`) — `init` wizard, `secret` management, `doctor`
|
|
45
|
+
(connectivity + REST-RBAC preflight), `overview`, `mcp`, and the `cluster` /
|
|
46
|
+
`vm` sub-commands (`vm delete` / `vm migrate` with `--dry-run` + double
|
|
47
|
+
confirm).
|
|
48
|
+
- **HTTP Basic-auth REST connection layer** over Prism Central `:9440` with
|
|
49
|
+
centralised teaching error translation.
|
|
50
|
+
|
|
51
|
+
### Known limitations
|
|
52
|
+
|
|
53
|
+
- Preview / mock-only: validated against mocked v4 responses; needs live
|
|
54
|
+
verification against a real Prism Central. Self-testable free on Nutanix
|
|
55
|
+
Community Edition (CE) + X-Small Prism Central.
|
|
56
|
+
- The **LCM update**, **PD failover**, and **ESXi-VM listing** paths in
|
|
57
|
+
particular are unverified against live systems.
|
|
58
|
+
- The Prism Central account needs REST API rights, not just Web UI access.
|
|
59
|
+
- Out of scope this release: IAM / users / roles, Files / Objects / Volumes
|
|
60
|
+
services, reports, X-Play playbooks, and anything outside Prism Central v4.
|
|
61
|
+
</content>
|
|
@@ -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,136 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: nutanix-aiops
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Governed AI-ops for Nutanix Prism Central (v4): cluster/VM/storage/network/DR/alert/LCM operations with automatic ETag & pagination handling and 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: cryptography>=42.0
|
|
10
|
+
Requires-Dist: httpx<1.0,>=0.27
|
|
11
|
+
Requires-Dist: mcp[cli]<2.0,>=1.10
|
|
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/nutanix-aiops -->
|
|
18
|
+
|
|
19
|
+
# Nutanix AIops (preview)
|
|
20
|
+
|
|
21
|
+
> **Disclaimer**: Community-maintained open-source project. **Not affiliated with, endorsed by, or sponsored by Nutanix.** Product and trademark names belong to their owners. MIT licensed.
|
|
22
|
+
|
|
23
|
+
Governed AI-ops for **Nutanix Prism Central** (v4 REST API) — clusters, hosts,
|
|
24
|
+
VMs (AHV + ESXi), storage, network, catalog, data protection / DR, alerts, LCM
|
|
25
|
+
upgrades, and capacity — with a **built-in governance harness**: unified audit
|
|
26
|
+
log, policy engine, token/runaway budget guard, undo-token recording, and
|
|
27
|
+
graduated-autonomy risk tiers. Connects to Prism Central on HTTPS `:9440` with
|
|
28
|
+
HTTP Basic auth (username + encrypted password). Self-contained: no dependencies
|
|
29
|
+
beyond `httpx` and the MCP SDK. **Preview — mock-validated only, not yet verified
|
|
30
|
+
against a live Prism Central.**
|
|
31
|
+
|
|
32
|
+
## Why this over a read-only Nutanix MCP
|
|
33
|
+
|
|
34
|
+
- **Automatic ETag / If-Match** on every mutation. The v4 API rejects an update
|
|
35
|
+
or delete without the entity's current ETag — the classic footgun. This tool
|
|
36
|
+
fetches and sends `If-Match` for you.
|
|
37
|
+
- **Automatic pagination** — list tools return the full set, not just page one.
|
|
38
|
+
- **Mixed-hypervisor VM listing** — `vm_list` returns both **AHV** and **ESXi**
|
|
39
|
+
guests under the same Prism Central (built for Broadcom→Nutanix migration
|
|
40
|
+
estates).
|
|
41
|
+
- **Governance harness** — audit / token+call budget / risk-tier approval /
|
|
42
|
+
undo-token / prompt-injection sanitize, with **dry-run + double-confirm** on
|
|
43
|
+
destructive writes.
|
|
44
|
+
|
|
45
|
+
## Capability matrix (47 MCP tools)
|
|
46
|
+
|
|
47
|
+
| Group | Tools | Count | R/W |
|
|
48
|
+
|-------|-------|:-----:|:---:|
|
|
49
|
+
| **Clusters** | `cluster_list`, `cluster_health`, `host_list`, `cluster_utilization` | 4 | 4 read |
|
|
50
|
+
| **VMs** | `vm_list`, `vm_get`, `vm_power_on`, `vm_guest_shutdown`, `vm_power_off`, `vm_reboot`, `vm_create`, `vm_update`, `vm_clone`, `vm_delete`, `vm_migrate` | 11 | 2 read · 9 write |
|
|
51
|
+
| **Storage** | `storage_container_list` / `_create` / `_update` / `_delete` | 4 | 1 read · 3 write |
|
|
52
|
+
| **Network** | `subnet_list`, `subnet_get`, `subnet_create`, `subnet_delete` | 4 | 2 read · 2 write |
|
|
53
|
+
| **Catalog** | `image_list`, `image_delete`, `category_list`, `category_create`, `category_assign` | 5 | 2 read · 3 write |
|
|
54
|
+
| **Data protection / DR** | `snapshot_list` / `_create` / `_delete` / `_restore`, `recovery_point_list`, `protection_domain_list`, `vm_protect`, `pd_failover` | 8 | 3 read · 5 write |
|
|
55
|
+
| **Alerts** | `alert_list`, `event_list`, `audit_list`, `analyze_alert` (RCA), `alert_acknowledge`, `alert_resolve` | 6 | 4 read · 2 write |
|
|
56
|
+
| **LCM (upgrades)** | `lcm_inventory`, `lcm_precheck`, `lcm_update` | 3 | 1 read · 2 write |
|
|
57
|
+
| **Capacity** | `task_list`, `capacity_runway` | 2 | 2 read |
|
|
58
|
+
| **Total** | | **47** | 21 read · 26 write |
|
|
59
|
+
|
|
60
|
+
`analyze_alert` is the flagship read: it correlates an alert with its related
|
|
61
|
+
events into a probable-cause + suggested-actions summary. High-risk writes
|
|
62
|
+
(`vm_delete`, `vm_migrate`, `storage_container_delete`, `subnet_delete`,
|
|
63
|
+
`snapshot_delete`, `snapshot_restore`, `pd_failover`, `image_delete`,
|
|
64
|
+
`lcm_update`) support `dry_run` and, at the CLI, double confirmation.
|
|
65
|
+
|
|
66
|
+
## Install
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
uv tool install nutanix-aiops # or: pipx install nutanix-aiops
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Quick start
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
nutanix-aiops init # wizard: PC host / port 9440 / username / verify_ssl + encrypted password
|
|
76
|
+
nutanix-aiops doctor # config, secrets, connectivity + REST-RBAC preflight
|
|
77
|
+
nutanix-aiops overview # one-shot estate summary
|
|
78
|
+
nutanix-aiops vm list # AHV + ESXi VMs
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Run as an MCP server (stdio):
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
export NUTANIX_AIOPS_MASTER_PASSWORD=... # unlock the encrypted secret store non-interactively
|
|
85
|
+
nutanix-aiops mcp
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## CLI
|
|
89
|
+
|
|
90
|
+
`nutanix-aiops` (Typer): `init`, `overview`, `doctor`, `mcp`; `cluster
|
|
91
|
+
list/health/hosts/util`; `vm list/get/power/delete/migrate` (`delete` & `migrate`
|
|
92
|
+
take `--dry-run` + double confirm); `secret set/list/rm/migrate/rotate-password`.
|
|
93
|
+
The CLI is a convenience subset — the full 47-tool surface is via the MCP server.
|
|
94
|
+
|
|
95
|
+
## Governance
|
|
96
|
+
|
|
97
|
+
Every MCP tool passes through the bundled `@governed_tool` harness:
|
|
98
|
+
|
|
99
|
+
- **Audit** — every call (params, result, status, duration, risk tier, approver,
|
|
100
|
+
rationale) is logged to `~/.nutanix-aiops/audit.db` (relocatable via
|
|
101
|
+
`NUTANIX_AIOPS_HOME`).
|
|
102
|
+
- **Budget / runaway guard** — token and call budgets trip a circuit breaker.
|
|
103
|
+
- **Risk tiers** — graduated autonomy; high-risk ops can require a named approver
|
|
104
|
+
(`NUTANIX_AUDIT_APPROVED_BY` / `NUTANIX_AUDIT_RATIONALE`).
|
|
105
|
+
- **Undo recording** — reversible writes record an inverse descriptor
|
|
106
|
+
(`vm_update` → prior CPU/memory, `vm_migrate` → prior host).
|
|
107
|
+
|
|
108
|
+
## Credentials
|
|
109
|
+
|
|
110
|
+
The Prism Central password is stored **encrypted** in
|
|
111
|
+
`~/.nutanix-aiops/secrets.enc` (Fernet + scrypt) — never plaintext on disk.
|
|
112
|
+
Unlock with a master password from `NUTANIX_AIOPS_MASTER_PASSWORD` (MCP/CI) or an
|
|
113
|
+
interactive prompt (CLI). The non-secret connection details (host, port,
|
|
114
|
+
username, verify_ssl) live in `~/.nutanix-aiops/config.yaml`. A legacy plaintext
|
|
115
|
+
env var `NUTANIX_<TARGET>_PASSWORD` is honoured as a fallback.
|
|
116
|
+
|
|
117
|
+
> **Gotcha:** the Prism Central account needs **REST API** rights, not just Web
|
|
118
|
+
> UI access. `doctor`'s REST-RBAC preflight catches this early.
|
|
119
|
+
|
|
120
|
+
## Supported scope & limitations
|
|
121
|
+
|
|
122
|
+
- **Preview / mock-only.** All behaviour is validated against mocked v4 REST
|
|
123
|
+
responses; it has not been run against a live Prism Central. The fastest live
|
|
124
|
+
check is `nutanix-aiops doctor`.
|
|
125
|
+
- **Self-testable free** on **Nutanix Community Edition (CE)**: a single-node CE
|
|
126
|
+
cluster + an X-Small Prism Central VM.
|
|
127
|
+
- **Least-verified paths:** LCM update (`lcm_update`), protection-domain failover
|
|
128
|
+
(`pd_failover`), and **ESXi-VM listing** in particular need live validation.
|
|
129
|
+
- **Out of scope this release:** IAM / users / roles, Files / Objects / Volumes
|
|
130
|
+
services, reports, X-Play playbooks, and anything outside Prism Central v4.
|
|
131
|
+
|
|
132
|
+
## Missing a capability?
|
|
133
|
+
|
|
134
|
+
Missing a tool, an API dialect, or a workflow? **Open an issue or PR** —
|
|
135
|
+
feedback and contributions are welcome.
|
|
136
|
+
</content>
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
<!-- mcp-name: io.github.AIops-tools/nutanix-aiops -->
|
|
2
|
+
|
|
3
|
+
# Nutanix AIops (preview)
|
|
4
|
+
|
|
5
|
+
> **Disclaimer**: Community-maintained open-source project. **Not affiliated with, endorsed by, or sponsored by Nutanix.** Product and trademark names belong to their owners. MIT licensed.
|
|
6
|
+
|
|
7
|
+
Governed AI-ops for **Nutanix Prism Central** (v4 REST API) — clusters, hosts,
|
|
8
|
+
VMs (AHV + ESXi), storage, network, catalog, data protection / DR, alerts, LCM
|
|
9
|
+
upgrades, and capacity — with a **built-in governance harness**: unified audit
|
|
10
|
+
log, policy engine, token/runaway budget guard, undo-token recording, and
|
|
11
|
+
graduated-autonomy risk tiers. Connects to Prism Central on HTTPS `:9440` with
|
|
12
|
+
HTTP Basic auth (username + encrypted password). Self-contained: no dependencies
|
|
13
|
+
beyond `httpx` and the MCP SDK. **Preview — mock-validated only, not yet verified
|
|
14
|
+
against a live Prism Central.**
|
|
15
|
+
|
|
16
|
+
## Why this over a read-only Nutanix MCP
|
|
17
|
+
|
|
18
|
+
- **Automatic ETag / If-Match** on every mutation. The v4 API rejects an update
|
|
19
|
+
or delete without the entity's current ETag — the classic footgun. This tool
|
|
20
|
+
fetches and sends `If-Match` for you.
|
|
21
|
+
- **Automatic pagination** — list tools return the full set, not just page one.
|
|
22
|
+
- **Mixed-hypervisor VM listing** — `vm_list` returns both **AHV** and **ESXi**
|
|
23
|
+
guests under the same Prism Central (built for Broadcom→Nutanix migration
|
|
24
|
+
estates).
|
|
25
|
+
- **Governance harness** — audit / token+call budget / risk-tier approval /
|
|
26
|
+
undo-token / prompt-injection sanitize, with **dry-run + double-confirm** on
|
|
27
|
+
destructive writes.
|
|
28
|
+
|
|
29
|
+
## Capability matrix (47 MCP tools)
|
|
30
|
+
|
|
31
|
+
| Group | Tools | Count | R/W |
|
|
32
|
+
|-------|-------|:-----:|:---:|
|
|
33
|
+
| **Clusters** | `cluster_list`, `cluster_health`, `host_list`, `cluster_utilization` | 4 | 4 read |
|
|
34
|
+
| **VMs** | `vm_list`, `vm_get`, `vm_power_on`, `vm_guest_shutdown`, `vm_power_off`, `vm_reboot`, `vm_create`, `vm_update`, `vm_clone`, `vm_delete`, `vm_migrate` | 11 | 2 read · 9 write |
|
|
35
|
+
| **Storage** | `storage_container_list` / `_create` / `_update` / `_delete` | 4 | 1 read · 3 write |
|
|
36
|
+
| **Network** | `subnet_list`, `subnet_get`, `subnet_create`, `subnet_delete` | 4 | 2 read · 2 write |
|
|
37
|
+
| **Catalog** | `image_list`, `image_delete`, `category_list`, `category_create`, `category_assign` | 5 | 2 read · 3 write |
|
|
38
|
+
| **Data protection / DR** | `snapshot_list` / `_create` / `_delete` / `_restore`, `recovery_point_list`, `protection_domain_list`, `vm_protect`, `pd_failover` | 8 | 3 read · 5 write |
|
|
39
|
+
| **Alerts** | `alert_list`, `event_list`, `audit_list`, `analyze_alert` (RCA), `alert_acknowledge`, `alert_resolve` | 6 | 4 read · 2 write |
|
|
40
|
+
| **LCM (upgrades)** | `lcm_inventory`, `lcm_precheck`, `lcm_update` | 3 | 1 read · 2 write |
|
|
41
|
+
| **Capacity** | `task_list`, `capacity_runway` | 2 | 2 read |
|
|
42
|
+
| **Total** | | **47** | 21 read · 26 write |
|
|
43
|
+
|
|
44
|
+
`analyze_alert` is the flagship read: it correlates an alert with its related
|
|
45
|
+
events into a probable-cause + suggested-actions summary. High-risk writes
|
|
46
|
+
(`vm_delete`, `vm_migrate`, `storage_container_delete`, `subnet_delete`,
|
|
47
|
+
`snapshot_delete`, `snapshot_restore`, `pd_failover`, `image_delete`,
|
|
48
|
+
`lcm_update`) support `dry_run` and, at the CLI, double confirmation.
|
|
49
|
+
|
|
50
|
+
## Install
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
uv tool install nutanix-aiops # or: pipx install nutanix-aiops
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Quick start
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
nutanix-aiops init # wizard: PC host / port 9440 / username / verify_ssl + encrypted password
|
|
60
|
+
nutanix-aiops doctor # config, secrets, connectivity + REST-RBAC preflight
|
|
61
|
+
nutanix-aiops overview # one-shot estate summary
|
|
62
|
+
nutanix-aiops vm list # AHV + ESXi VMs
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Run as an MCP server (stdio):
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
export NUTANIX_AIOPS_MASTER_PASSWORD=... # unlock the encrypted secret store non-interactively
|
|
69
|
+
nutanix-aiops mcp
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## CLI
|
|
73
|
+
|
|
74
|
+
`nutanix-aiops` (Typer): `init`, `overview`, `doctor`, `mcp`; `cluster
|
|
75
|
+
list/health/hosts/util`; `vm list/get/power/delete/migrate` (`delete` & `migrate`
|
|
76
|
+
take `--dry-run` + double confirm); `secret set/list/rm/migrate/rotate-password`.
|
|
77
|
+
The CLI is a convenience subset — the full 47-tool surface is via the MCP server.
|
|
78
|
+
|
|
79
|
+
## Governance
|
|
80
|
+
|
|
81
|
+
Every MCP tool passes through the bundled `@governed_tool` harness:
|
|
82
|
+
|
|
83
|
+
- **Audit** — every call (params, result, status, duration, risk tier, approver,
|
|
84
|
+
rationale) is logged to `~/.nutanix-aiops/audit.db` (relocatable via
|
|
85
|
+
`NUTANIX_AIOPS_HOME`).
|
|
86
|
+
- **Budget / runaway guard** — token and call budgets trip a circuit breaker.
|
|
87
|
+
- **Risk tiers** — graduated autonomy; high-risk ops can require a named approver
|
|
88
|
+
(`NUTANIX_AUDIT_APPROVED_BY` / `NUTANIX_AUDIT_RATIONALE`).
|
|
89
|
+
- **Undo recording** — reversible writes record an inverse descriptor
|
|
90
|
+
(`vm_update` → prior CPU/memory, `vm_migrate` → prior host).
|
|
91
|
+
|
|
92
|
+
## Credentials
|
|
93
|
+
|
|
94
|
+
The Prism Central password is stored **encrypted** in
|
|
95
|
+
`~/.nutanix-aiops/secrets.enc` (Fernet + scrypt) — never plaintext on disk.
|
|
96
|
+
Unlock with a master password from `NUTANIX_AIOPS_MASTER_PASSWORD` (MCP/CI) or an
|
|
97
|
+
interactive prompt (CLI). The non-secret connection details (host, port,
|
|
98
|
+
username, verify_ssl) live in `~/.nutanix-aiops/config.yaml`. A legacy plaintext
|
|
99
|
+
env var `NUTANIX_<TARGET>_PASSWORD` is honoured as a fallback.
|
|
100
|
+
|
|
101
|
+
> **Gotcha:** the Prism Central account needs **REST API** rights, not just Web
|
|
102
|
+
> UI access. `doctor`'s REST-RBAC preflight catches this early.
|
|
103
|
+
|
|
104
|
+
## Supported scope & limitations
|
|
105
|
+
|
|
106
|
+
- **Preview / mock-only.** All behaviour is validated against mocked v4 REST
|
|
107
|
+
responses; it has not been run against a live Prism Central. The fastest live
|
|
108
|
+
check is `nutanix-aiops doctor`.
|
|
109
|
+
- **Self-testable free** on **Nutanix Community Edition (CE)**: a single-node CE
|
|
110
|
+
cluster + an X-Small Prism Central VM.
|
|
111
|
+
- **Least-verified paths:** LCM update (`lcm_update`), protection-domain failover
|
|
112
|
+
(`pd_failover`), and **ESXi-VM listing** in particular need live validation.
|
|
113
|
+
- **Out of scope this release:** IAM / users / roles, Files / Objects / Volumes
|
|
114
|
+
services, reports, X-Play playbooks, and anything outside Prism Central v4.
|
|
115
|
+
|
|
116
|
+
## Missing a capability?
|
|
117
|
+
|
|
118
|
+
Missing a tool, an API dialect, or a workflow? **Open an issue or PR** —
|
|
119
|
+
feedback and contributions are welcome.
|
|
120
|
+
</content>
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Nutanix AIops v0.1.0 — preview
|
|
2
|
+
|
|
3
|
+
Governed AI-ops for **Nutanix Prism Central** (v4 REST API) for AI agents, with a
|
|
4
|
+
built-in governance harness (audit, policy, token/runaway budget, undo-token
|
|
5
|
+
recording, graduated risk tiers) and an encrypted credential store. Standalone —
|
|
6
|
+
no external skill-family dependency.
|
|
7
|
+
|
|
8
|
+
> **Preview / mock-only.** All behaviour is validated against mocked v4 REST
|
|
9
|
+
> responses; it has not been run against a live Prism Central. The fastest live
|
|
10
|
+
> check is `nutanix-aiops doctor`.
|
|
11
|
+
|
|
12
|
+
## Highlights
|
|
13
|
+
|
|
14
|
+
- **47 MCP tools** (21 read, 26 write), every one wrapped with `@governed_tool`,
|
|
15
|
+
across nine groups:
|
|
16
|
+
- **Clusters** (read) — `cluster_list`, `cluster_health`, `host_list`,
|
|
17
|
+
`cluster_utilization`.
|
|
18
|
+
- **VMs** — `vm_list` (AHV + ESXi), `vm_get` (surfaces ETag); writes
|
|
19
|
+
`vm_power_on` / `vm_guest_shutdown` / `vm_power_off` / `vm_reboot` /
|
|
20
|
+
`vm_create` / `vm_update` (undo prior CPU/mem) / `vm_clone` / `vm_delete`
|
|
21
|
+
(HIGH, dry-run) / `vm_migrate` (HIGH, dry-run, undo → prior host).
|
|
22
|
+
- **Storage** — container list / create / update (undo prior) / delete (HIGH).
|
|
23
|
+
- **Network** — subnet list / get (ETag) / create / delete (HIGH).
|
|
24
|
+
- **Catalog** — image list / delete (HIGH); category list / create / assign
|
|
25
|
+
(bulk).
|
|
26
|
+
- **Data protection / DR** — snapshot list / create / delete (HIGH) / restore
|
|
27
|
+
(HIGH), `recovery_point_list`, `protection_domain_list`, `vm_protect`,
|
|
28
|
+
`pd_failover` (HIGH).
|
|
29
|
+
- **Alerts** — `alert_list`, `event_list`, `audit_list`, **`analyze_alert`**
|
|
30
|
+
(the flagship RCA read), `alert_acknowledge`, `alert_resolve`.
|
|
31
|
+
- **LCM** — `lcm_inventory`, `lcm_precheck`, `lcm_update` (HIGH firmware/software).
|
|
32
|
+
- **Capacity** — `task_list`, `capacity_runway` (days-to-full forecast).
|
|
33
|
+
- **Automatic ETag / If-Match** on every mutation (the v4 footgun) and
|
|
34
|
+
**automatic pagination** on every list; `vm_list` returns **AHV + ESXi**.
|
|
35
|
+
- **Encrypted password store** (`~/.nutanix-aiops/secrets.enc`, Fernet + scrypt)
|
|
36
|
+
— never plaintext on disk; legacy `NUTANIX_<TARGET>_PASSWORD` env fallback.
|
|
37
|
+
- **CLI** with an `init` onboarding wizard, `secret` management, `overview`,
|
|
38
|
+
`cluster` / `vm` sub-commands, and a `doctor` with a REST-RBAC preflight.
|
|
39
|
+
- **Basic-auth REST connection layer** over Prism Central `:9440` with teaching
|
|
40
|
+
error translation.
|
|
41
|
+
|
|
42
|
+
## Install
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
uv tool install nutanix-aiops
|
|
46
|
+
nutanix-aiops init
|
|
47
|
+
nutanix-aiops doctor
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Caveats
|
|
51
|
+
|
|
52
|
+
- The Prism Central account needs **REST API** rights, not just Web UI access.
|
|
53
|
+
- Self-testable free on **Nutanix Community Edition (CE)** + X-Small Prism
|
|
54
|
+
Central. The **LCM update**, **PD failover**, and **ESXi-VM listing** paths in
|
|
55
|
+
particular need live verification.
|
|
56
|
+
- Out of scope this release: IAM / users / roles, Files / Objects / Volumes
|
|
57
|
+
services, reports, X-Play playbooks, and anything outside Prism Central v4.
|
|
58
|
+
</content>
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
## Disclaimer
|
|
4
|
+
|
|
5
|
+
Community-maintained open-source project. **Not affiliated with, endorsed by, or
|
|
6
|
+
sponsored by Nutanix, Inc.** Product and trademark names (Nutanix, Prism, AHV)
|
|
7
|
+
belong to their owners. 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/Nutanix-AIops](https://github.com/AIops-tools/Nutanix-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 Prism Central passwords live **encrypted** in
|
|
20
|
+
`~/.nutanix-aiops/secrets.enc` (Fernet/AES-128 + scrypt-derived key; chmod
|
|
21
|
+
600), never in `config.yaml` and never in source. The master password is
|
|
22
|
+
never stored — only a per-store random salt and the ciphertext are on disk.
|
|
23
|
+
- A legacy plaintext env var `NUTANIX_<TARGET_NAME_UPPER>_PASSWORD` is still
|
|
24
|
+
honoured as a fallback with a deprecation warning (migrate with
|
|
25
|
+
`nutanix-aiops secret migrate`).
|
|
26
|
+
- The password is used for HTTP Basic auth at request time and held only in
|
|
27
|
+
memory. It is never logged or echoed; the config file holds only host, port,
|
|
28
|
+
username, and TLS settings. Note: the Prism Central account needs REST API
|
|
29
|
+
rights, not just WebUI access.
|
|
30
|
+
|
|
31
|
+
### Governed Operations
|
|
32
|
+
Every MCP tool runs through the bundled `@governed_tool` harness
|
|
33
|
+
(`nutanix_aiops.governance`):
|
|
34
|
+
- **Audit** — every call logged to a local SQLite DB under `~/.nutanix-aiops/`
|
|
35
|
+
(relocatable via `NUTANIX_AIOPS_HOME`), agent-attributed, secret-redacted.
|
|
36
|
+
- **Token/runaway budget** — hard ceilings (`NUTANIX_MAX_TOOL_CALLS` /
|
|
37
|
+
`NUTANIX_MAX_TOOL_SECONDS`) plus an on-by-default guard that trips a tight
|
|
38
|
+
poll/retry loop, preventing unbounded API consumption (e.g. polling a slow
|
|
39
|
+
session).
|
|
40
|
+
- **Graduated risk tiers** — `~/.nutanix-aiops/rules.yaml` `risk_tiers` gate
|
|
41
|
+
writes by environment/tag; the highest tiers require a recorded approver.
|
|
42
|
+
- **Undo-token recording** — reversible writes capture the entity's BEFORE state
|
|
43
|
+
and record an inverse descriptor (e.g. `vm_power_on`→re-power to prior state,
|
|
44
|
+
`vm_update`→restore prior CPU/memory, `vm_migrate`→migrate back to the prior
|
|
45
|
+
host) so the change can be rolled back.
|
|
46
|
+
- **Automatic ETag / If-Match** — every mutation first fetches the entity's
|
|
47
|
+
current ETag and sends it back as `If-Match`, preventing lost-update (mid-air
|
|
48
|
+
collision) races the v4 API would otherwise reject.
|
|
49
|
+
|
|
50
|
+
### State-Changing Operations
|
|
51
|
+
Destructive writes — `vm_delete`, `vm_migrate`, `storage_container_delete`,
|
|
52
|
+
`subnet_delete`, `image_delete`, `snapshot_delete`, `snapshot_restore`,
|
|
53
|
+
`pd_failover`, `lcm_update` — are `risk_level=high`, accept a `dry_run` preview,
|
|
54
|
+
and (under `risk_tiers`) require a recorded approver (`NUTANIX_AUDIT_APPROVED_BY`
|
|
55
|
+
+ `NUTANIX_AUDIT_RATIONALE`). The CLI additionally double-confirms `vm delete`
|
|
56
|
+
and `vm migrate` and supports `--dry-run`. Reversible medium/low writes capture
|
|
57
|
+
before-state and, where a safe inverse exists, record an undo token.
|
|
58
|
+
|
|
59
|
+
### SSL/TLS Verification
|
|
60
|
+
`verify_ssl` defaults to true; disable only for self-signed lab certificates.
|
|
61
|
+
|
|
62
|
+
### Prompt-Injection Protection
|
|
63
|
+
All server-returned text (VM/cluster names, alert titles, extIds, event fields)
|
|
64
|
+
is passed through a `sanitize()` truncate + control-character strip before
|
|
65
|
+
reaching the agent.
|
|
66
|
+
|
|
67
|
+
### Network Scope
|
|
68
|
+
No webhooks, no telemetry, no outbound calls beyond the configured Prism Central
|
|
69
|
+
REST API endpoint (HTTPS :9440). No post-install scripts or background services.
|
|
70
|
+
|
|
71
|
+
## Static Analysis
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
uvx bandit -r nutanix_aiops/ mcp_server/
|
|
75
|
+
uv run ruff check .
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Supported Versions
|
|
79
|
+
|
|
80
|
+
The latest released version receives security fixes. This is a preview (0.x);
|
|
81
|
+
pin a version in production.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""MCP server package for nutanix-aiops."""
|
|
@@ -0,0 +1,100 @@
|
|
|
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 nutanix_aiops.config import load_config
|
|
23
|
+
from nutanix_aiops.connection import ConnectionManager, NutanixApiError
|
|
24
|
+
from nutanix_aiops.governance import sanitize
|
|
25
|
+
|
|
26
|
+
logger = logging.getLogger(__name__)
|
|
27
|
+
|
|
28
|
+
_DOCTOR_HINT = "Run 'nutanix-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
|
+
NutanixApiError,
|
|
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
|
+
"nutanix-aiops",
|
|
77
|
+
instructions=(
|
|
78
|
+
"Nutanix Prism Central (v4) operations (preview): clusters/hosts and "
|
|
79
|
+
"utilization; VM inventory (AHV + ESXi) and lifecycle (power / create / "
|
|
80
|
+
"update / clone / migrate / delete); storage containers; subnets; images "
|
|
81
|
+
"and categories; snapshots / recovery points and protection domains; "
|
|
82
|
+
"alerts / events (list, acknowledge, resolve, analyze); and LCM upgrades. "
|
|
83
|
+
"Mutations auto-handle the v4 ETag/If-Match footgun and auto-paginate. "
|
|
84
|
+
"Destructive writes (delete / migrate / pool changes) are risk=high with a "
|
|
85
|
+
"dry_run preview and require an approver. Every tool runs through the "
|
|
86
|
+
"nutanix-aiops governance harness (audit / budget / risk-tier / undo)."
|
|
87
|
+
),
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
_conn_mgr: Optional[ConnectionManager] = None
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def _get_connection(target: Optional[str] = None) -> Any:
|
|
94
|
+
"""Return a Nutanix connection, lazily initialising the manager."""
|
|
95
|
+
global _conn_mgr # noqa: PLW0603
|
|
96
|
+
if _conn_mgr is None:
|
|
97
|
+
config_path_str = os.environ.get("NUTANIX_AIOPS_CONFIG")
|
|
98
|
+
config_path = Path(config_path_str) if config_path_str else None
|
|
99
|
+
_conn_mgr = ConnectionManager(load_config(config_path))
|
|
100
|
+
return _conn_mgr.connect(target)
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"""MCP server wrapping nutanix-aiops operations (stdio transport).
|
|
2
|
+
|
|
3
|
+
Thin adapter layer: each ``@mcp.tool()`` function (in ``mcp_server/tools/``)
|
|
4
|
+
delegates to the ``nutanix_aiops`` ops package and is wrapped with the
|
|
5
|
+
nutanix-aiops ``@governed_tool`` harness (audit / budget / undo / risk-tier).
|
|
6
|
+
|
|
7
|
+
Standalone, self-governed Nutanix Prism Central (v4) operations (preview).
|
|
8
|
+
Cluster / VM / storage / network / snapshot-DR / alert / LCM management with
|
|
9
|
+
automatic ETag & pagination handling.
|
|
10
|
+
|
|
11
|
+
Source: https://github.com/AIops-tools/Nutanix-AIops
|
|
12
|
+
License: MIT
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import logging
|
|
16
|
+
|
|
17
|
+
from mcp_server._shared import _safe_error, mcp, tool_errors
|
|
18
|
+
|
|
19
|
+
# Importing the tool modules registers every @mcp.tool() onto the shared
|
|
20
|
+
# `mcp` instance. Order does not matter; each module is self-contained.
|
|
21
|
+
from mcp_server.tools import ( # noqa: F401 — side effects
|
|
22
|
+
alerts,
|
|
23
|
+
capacity,
|
|
24
|
+
catalog,
|
|
25
|
+
clusters,
|
|
26
|
+
dataprotection,
|
|
27
|
+
lcm,
|
|
28
|
+
network,
|
|
29
|
+
storage,
|
|
30
|
+
vms,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
__all__ = ["mcp", "main", "_safe_error", "tool_errors"]
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def main() -> None:
|
|
37
|
+
"""Run the MCP server over stdio."""
|
|
38
|
+
logging.basicConfig(level=logging.INFO)
|
|
39
|
+
mcp.run(transport="stdio")
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""MCP tool modules. Importing each registers its @mcp.tool() functions."""
|