vmware-storage 2.0.0__tar.gz → 2.2.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.
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/.claude-plugin/plugin.json +1 -1
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/.mcp.json +1 -1
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/PKG-INFO +3 -3
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/RELEASE_NOTES.md +36 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/openclaw.plugin.json +1 -1
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/package.json +1 -1
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/pyproject.toml +3 -3
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/server.json +2 -2
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/skills/vmware-storage/SKILL.md +2 -2
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/skills/vmware-storage/references/setup-guide.md +30 -3
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/capability/_family.py +9 -7
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/uv.lock +6 -6
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/vmware_storage/__init__.py +1 -1
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/vmware_storage/cli.py +39 -5
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/vmware_storage/mcp_server/server.py +19 -3
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/.clawhubignore +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/.env.example +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/.gitignore +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/Dockerfile +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/LICENSE +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/README-CN.md +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/README.md +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/SECURITY.md +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/config.example.yaml +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/docker-compose.yml +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/examples/mcp-configs/README.md +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/examples/mcp-configs/claude-code.json +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/examples/mcp-configs/continue.yaml +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/examples/mcp-configs/cursor.json +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/examples/mcp-configs/goose.json +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/examples/mcp-configs/localcowork.json +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/examples/mcp-configs/mcp-agent.yaml +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/examples/mcp-configs/vscode-copilot.json +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/patterns/README.md +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/patterns/iscsi-target-stale-rescan.yaml +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/skills/vmware-storage/evals/evals.json +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/skills/vmware-storage/references/agent-guardrails.md +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/skills/vmware-storage/references/capabilities.md +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/skills/vmware-storage/references/cli-reference.md +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/smithery.yaml +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/__init__.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/conftest.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/__init__.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/capability/__init__.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/capability/_scores.json +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/capability/_scoring.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/capability/_skill.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/capability/conftest.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/capability/test_entity_reachability.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/capability/test_error_actionability.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/capability/test_tool_description_quality.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/capability/test_tool_manifest_budget.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/__init__.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_atexit_handlers_do_not_accumulate.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_audit_isolation.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_cached_loader_agrees_with_the_resolver.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_capability_grader.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_cli_writes_guarded.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_credential_env_override.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_datastore_list_renders.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_doctor_authenticates_every_target.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_doctor_uses_the_config_the_tools_use.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_env_secret_obfuscation.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_fc_multipath.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_instructions_name_targets.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_inventory_scale_n1.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_iscsi_unreachable_host.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_release_blockers.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_remedy_survives_a_long_home.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_result_envelope.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_returned_failure_is_audited.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_session_probe_eviction.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_storage_hardening_fixes.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_storage_ops_behavior.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_tool_names_2_0.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_vim_attribute_conformance.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_vsan_efficiency.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_vsan_health_is_actually_queried.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_vsan_reports_what_it_could_not_read.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/spec/__init__.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/spec/vsan_efficiency_endpoints.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/spec/vsan_health_endpoints.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/test_init_and_onboarding.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/test_iscsi_gate.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/test_no_destructive_ops.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/test_no_destructive_vm_code.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/test_safe_error_passthrough.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/test_stop_signal_runs_atexit.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/vmware_storage/config.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/vmware_storage/connection.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/vmware_storage/doctor.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/vmware_storage/init_wizard.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/vmware_storage/mcp_server/__init__.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/vmware_storage/mcp_server/__main__.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/vmware_storage/notify/__init__.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/vmware_storage/notify/audit.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/vmware_storage/ops/__init__.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/vmware_storage/ops/datastore_browser.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/vmware_storage/ops/inventory.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/vmware_storage/ops/iscsi_config.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/vmware_storage/ops/iscsi_gate.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/vmware_storage/ops/multipath.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/vmware_storage/ops/storage_paths.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/vmware_storage/ops/vsan.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/vmware_storage/ops/vsan_efficiency.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/vmware_storage/ops/vsan_sdk.py +0 -0
- {vmware_storage-2.0.0 → vmware_storage-2.2.0}/vmware_storage/policy_environment.py +0 -0
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://anthropic.com/claude-code/plugin.schema.json",
|
|
3
3
|
"name": "vmware-storage",
|
|
4
4
|
"displayName": "VMware Storage",
|
|
5
|
-
"version": "2.
|
|
5
|
+
"version": "2.2.0",
|
|
6
6
|
"description": "VMware vSphere storage with 14 MCP tools: datastores, iSCSI, vSAN, FC multipath.",
|
|
7
7
|
"author": {
|
|
8
8
|
"name": "Wei Zhou",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: vmware-storage
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.2.0
|
|
4
4
|
Summary: VMware vSphere storage management: datastores, iSCSI, vSAN. Domain-focused MCP skill.
|
|
5
5
|
Project-URL: Homepage, https://github.com/vmware-skills/VMware-Storage
|
|
6
6
|
Project-URL: Repository, https://github.com/vmware-skills/VMware-Storage
|
|
@@ -10,13 +10,13 @@ Author-email: Wei Zhou <wei-wz.zhou@broadcom.com>
|
|
|
10
10
|
License-Expression: MIT
|
|
11
11
|
License-File: LICENSE
|
|
12
12
|
Requires-Python: >=3.10
|
|
13
|
-
Requires-Dist: mcp[cli]<2.0,>=1.
|
|
13
|
+
Requires-Dist: mcp[cli]<2.0,>=1.28
|
|
14
14
|
Requires-Dist: pyaml<27.0,>=24.0
|
|
15
15
|
Requires-Dist: python-dotenv<2.0,>=1.0
|
|
16
16
|
Requires-Dist: pyvmomi<10.0,>=8.0.3.0
|
|
17
17
|
Requires-Dist: rich<15.0,>=13.0
|
|
18
18
|
Requires-Dist: typer<1.0,>=0.12
|
|
19
|
-
Requires-Dist: vmware-policy<2.0,>=1.
|
|
19
|
+
Requires-Dist: vmware-policy<2.0,>=1.21.0
|
|
20
20
|
Description-Content-Type: text/markdown
|
|
21
21
|
|
|
22
22
|
<!-- mcp-name: io.github.vmware-skills/vmware-storage -->
|
|
@@ -1,3 +1,39 @@
|
|
|
1
|
+
## v2.2.0 — serve MCP over HTTPS
|
|
2
|
+
|
|
3
|
+
`vmware-storage mcp` can now serve the network as well as stdio (HLD §16, via vmware-policy 1.21.0):
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
vmware-audit token create alice # once per caller; shown once
|
|
7
|
+
vmware-storage mcp --transport https --host 0.0.0.0 --port 8443 \
|
|
8
|
+
--cert server.pem --key server-key.pem --public-name mcp.example.com
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
* Every request needs `Authorization: Bearer <token>`; the server will not start without a token, refuses Host or
|
|
12
|
+
Origin values outside `--public-name`, and checks itself (unauthenticated requests must get 401) before it
|
|
13
|
+
binds. `--transport http` binds loopback only, for a TLS-terminating reverse proxy.
|
|
14
|
+
* Audit rows record the caller as `token:<name>` and the surface as `mcp-https`. Calls naming different targets
|
|
15
|
+
run in parallel; calls naming no target run one at a time.
|
|
16
|
+
* stdio remains the default; the `vmware-storage-mcp` console script and `python -m` are unchanged.
|
|
17
|
+
* Everyone who can reach the endpoint acts with this server's account; run one endpoint per privilege level.
|
|
18
|
+
* Requires `vmware-policy>=1.21.0` and `mcp>=1.28`.
|
|
19
|
+
|
|
20
|
+
## v2.1.0 — offer only read tools, plus chosen write tools
|
|
21
|
+
|
|
22
|
+
`vmware-storage mcp` can now offer a subset of this server's tools (HLD §17 D-16, via vmware-policy 1.20.0):
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
vmware-storage mcp --expose read --allow-write enable_iscsi
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
* `--expose read` (or `VMWARE_STORAGE_MCP_EXPOSE=read`) keeps only tools annotated `readOnlyHint: true`; `--allow-write a,b`
|
|
29
|
+
(or `VMWARE_STORAGE_MCP_ALLOW_WRITE`) keeps chosen write tools on top. The default is unchanged: every tool.
|
|
30
|
+
* A bad value, or a name that is not a write tool of this server, stops the server before it serves (exit 2).
|
|
31
|
+
Flags and environment variables are not mixed; a blank flag counts as not given. Pre-2.0 names are accepted.
|
|
32
|
+
* This limits what clients are offered; it is not authorization. See "Limiting which tools are offered" in
|
|
33
|
+
`references/setup-guide.md`, which also notes that an agent with a shell can bypass MCP, so the account itself
|
|
34
|
+
must be least-privilege.
|
|
35
|
+
* Requires `vmware-policy>=1.20.0`.
|
|
36
|
+
|
|
1
37
|
## v2.0.0 — MCP tools renamed verb-first
|
|
2
38
|
|
|
3
39
|
**Breaking for MCP clients:** the server exposes only the new tool names. The family now follows one naming
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "vmware-storage"
|
|
7
|
-
version = "2.
|
|
7
|
+
version = "2.2.0"
|
|
8
8
|
description = "VMware vSphere storage management: datastores, iSCSI, vSAN. Domain-focused MCP skill."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
@@ -16,8 +16,8 @@ dependencies = [
|
|
|
16
16
|
"typer>=0.12,<1.0",
|
|
17
17
|
"rich>=13.0,<15.0",
|
|
18
18
|
"python-dotenv>=1.0,<2.0",
|
|
19
|
-
"mcp[cli]>=1.
|
|
20
|
-
"vmware-policy>=1.
|
|
19
|
+
"mcp[cli]>=1.28,<2.0",
|
|
20
|
+
"vmware-policy>=1.21.0,<2.0",
|
|
21
21
|
]
|
|
22
22
|
|
|
23
23
|
|
|
@@ -7,12 +7,12 @@
|
|
|
7
7
|
"url": "https://github.com/vmware-skills/VMware-Storage",
|
|
8
8
|
"source": "github"
|
|
9
9
|
},
|
|
10
|
-
"version": "2.
|
|
10
|
+
"version": "2.2.0",
|
|
11
11
|
"packages": [
|
|
12
12
|
{
|
|
13
13
|
"registryType": "pypi",
|
|
14
14
|
"identifier": "vmware-storage",
|
|
15
|
-
"version": "2.
|
|
15
|
+
"version": "2.2.0",
|
|
16
16
|
"runtimeHint": "uvx",
|
|
17
17
|
"packageArguments": [
|
|
18
18
|
{
|
|
@@ -39,7 +39,7 @@ VMware vSphere storage management — 14 MCP tools for datastores, iSCSI, vSAN,
|
|
|
39
39
|
## Quick Install
|
|
40
40
|
|
|
41
41
|
```bash
|
|
42
|
-
uv tool install vmware-storage==2.
|
|
42
|
+
uv tool install vmware-storage==2.2.0
|
|
43
43
|
vmware-storage init # guided setup: writes config + .env (chmod 600, password grep-safe), then verifies
|
|
44
44
|
vmware-storage doctor
|
|
45
45
|
```
|
|
@@ -263,7 +263,7 @@ Corporate TLS proxies inject certificates that uv's bundled CA store doesn't tru
|
|
|
263
263
|
## Setup
|
|
264
264
|
|
|
265
265
|
```bash
|
|
266
|
-
uv tool install vmware-storage==2.
|
|
266
|
+
uv tool install vmware-storage==2.2.0
|
|
267
267
|
mkdir -p ~/.vmware-storage
|
|
268
268
|
cp config.example.yaml ~/.vmware-storage/config.yaml
|
|
269
269
|
# Edit config.yaml with your vCenter/ESXi targets
|
{vmware_storage-2.0.0 → vmware_storage-2.2.0}/skills/vmware-storage/references/setup-guide.md
RENAMED
|
@@ -13,19 +13,19 @@ Complete setup and security guide for `vmware-storage`.
|
|
|
13
13
|
### Via uv (recommended)
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
|
-
uv tool install vmware-storage==2.
|
|
16
|
+
uv tool install vmware-storage==2.2.0
|
|
17
17
|
```
|
|
18
18
|
|
|
19
19
|
### Via pip
|
|
20
20
|
|
|
21
21
|
```bash
|
|
22
|
-
pip install vmware-storage==2.
|
|
22
|
+
pip install vmware-storage==2.2.0
|
|
23
23
|
```
|
|
24
24
|
|
|
25
25
|
### From source
|
|
26
26
|
|
|
27
27
|
```bash
|
|
28
|
-
git clone --branch v2.
|
|
28
|
+
git clone --branch v2.2.0 https://github.com/vmware-skills/VMware-Storage.git
|
|
29
29
|
cd VMware-Storage
|
|
30
30
|
pip install -e .
|
|
31
31
|
```
|
|
@@ -190,6 +190,33 @@ whitespace are handled correctly).
|
|
|
190
190
|
> Secrets Manager, or a Kubernetes Secret) into the `*_PASSWORD` environment
|
|
191
191
|
> variable at process start. The code reads the env var either way.
|
|
192
192
|
|
|
193
|
+
## Limiting which tools are offered
|
|
194
|
+
|
|
195
|
+
By default the MCP server offers every tool. To offer only read tools, start it with `--expose read`, or set
|
|
196
|
+
`VMWARE_STORAGE_MCP_EXPOSE=read` in the MCP client's `env` block (useful when the client launches `vmware-storage mcp` itself). To offer
|
|
197
|
+
chosen write tools as well, add `--allow-write` with a comma-separated list (or `VMWARE_STORAGE_MCP_ALLOW_WRITE`):
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
vmware-storage mcp --expose read --allow-write enable_iscsi
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
- A read tool is one annotated `readOnlyHint: true`; every other tool counts as a write.
|
|
204
|
+
- An unknown setting, or a name that is not a write tool of this server, stops the server before it serves (exit
|
|
205
|
+
code 2), so it never offers more than you asked for. Pre-2.0 tool names are accepted.
|
|
206
|
+
- With `--expose read`, the server prints one line to stderr saying what it exposes.
|
|
207
|
+
- Flags and environment variables are not mixed: if either flag is given, both environment variables are
|
|
208
|
+
ignored, so a leftover `_ALLOW_WRITE` in the shell cannot widen `--expose read`. A blank flag value counts as
|
|
209
|
+
not given.
|
|
210
|
+
- A tool that runs other steps (a plan, workflow or batch tool) carries every write it can execute, including
|
|
211
|
+
writes this setting hides. Expose such a tool only if you would expose those writes too.
|
|
212
|
+
- A launcher that imports the server object can call
|
|
213
|
+
`vmware_policy.exposure.restrict_tools(mcp, skill="storage", expose="read", allow_write=[...])` before running it,
|
|
214
|
+
instead of editing the SDK's tool registry.
|
|
215
|
+
- This limits what clients are offered. It is **not** authorization: whether a call may change anything is decided by
|
|
216
|
+
the account's permissions, and deny rules in `~/.vmware/rules.yaml` still apply to every exposed tool.
|
|
217
|
+
- An agent that can run shell commands can also reach the platform without MCP (SSH, curl, govc, PowerCLI). So
|
|
218
|
+
the service account itself must be least-privilege: exposure and deny rules are guardrails, not the boundary.
|
|
219
|
+
|
|
193
220
|
## Security Details
|
|
194
221
|
|
|
195
222
|
> **Disclaimer**: This is a community-maintained open-source project and is **not affiliated with, endorsed by, or sponsored by VMware, Inc. or Broadcom Inc.** "VMware" and "vSphere" are trademarks of Broadcom.
|
|
@@ -104,9 +104,10 @@ FAMILY_TOOLS: dict[str, frozenset[str]] = {
|
|
|
104
104
|
'update_dfw_policy', 'update_dfw_rule',
|
|
105
105
|
}),
|
|
106
106
|
'vmware-pilot': frozenset({
|
|
107
|
-
'approve', 'cancel_workflow', 'confirm_draft', 'create_workflow',
|
|
108
|
-
'
|
|
109
|
-
'
|
|
107
|
+
'approve', 'cancel_workflow', 'confirm_draft', 'create_workflow',
|
|
108
|
+
'create_workflow_from_template', 'design_workflow', 'get_skill_catalog',
|
|
109
|
+
'get_workflow_status', 'list_workflows', 'review_workflow', 'rollback',
|
|
110
|
+
'run_workflow', 'update_draft',
|
|
110
111
|
}),
|
|
111
112
|
'vmware-storage': frozenset({
|
|
112
113
|
'add_iscsi_target', 'browse_datastore', 'enable_iscsi', 'get_iscsi_status',
|
|
@@ -118,10 +119,11 @@ FAMILY_TOOLS: dict[str, frozenset[str]] = {
|
|
|
118
119
|
'vmware-vks': frozenset({
|
|
119
120
|
'check_vks_compatibility', 'create_namespace', 'create_tkc_cluster',
|
|
120
121
|
'delete_namespace', 'delete_tkc_cluster', 'get_harbor_info', 'get_namespace',
|
|
121
|
-
'
|
|
122
|
-
'
|
|
123
|
-
'
|
|
124
|
-
'
|
|
122
|
+
'get_supervisor_status', 'get_tkc_available_versions', 'get_tkc_cluster',
|
|
123
|
+
'issue_supervisor_kubeconfig', 'issue_tkc_kubeconfig',
|
|
124
|
+
'list_namespace_storage_usage', 'list_namespaces',
|
|
125
|
+
'list_supervisor_storage_policies', 'list_tkc_clusters', 'list_vm_classes',
|
|
126
|
+
'list_vm_service_groups', 'list_vm_service_network_interfaces',
|
|
125
127
|
'list_vm_service_snapshots', 'scale_tkc_cluster', 'update_namespace',
|
|
126
128
|
'upgrade_tkc_cluster',
|
|
127
129
|
}),
|
|
@@ -1162,21 +1162,21 @@ wheels = [
|
|
|
1162
1162
|
|
|
1163
1163
|
[[package]]
|
|
1164
1164
|
name = "vmware-policy"
|
|
1165
|
-
version = "1.
|
|
1165
|
+
version = "1.21.0"
|
|
1166
1166
|
source = { registry = "https://pypi.org/simple" }
|
|
1167
1167
|
dependencies = [
|
|
1168
1168
|
{ name = "pyyaml" },
|
|
1169
1169
|
{ name = "rich" },
|
|
1170
1170
|
{ name = "typer" },
|
|
1171
1171
|
]
|
|
1172
|
-
sdist = { url = "https://files.pythonhosted.org/packages/5d/
|
|
1172
|
+
sdist = { url = "https://files.pythonhosted.org/packages/87/5d/4221ea4a344ec33d6b54903682ce8ae2013bb0a2d6137c94ac769690ea8b/vmware_policy-1.21.0.tar.gz", hash = "sha256:f42b794ea69e52e1fa13aff8b5bc07631d82683b1c12872f2f2ec744e3853549", size = 303862, upload-time = "2026-10-15T10:13:33.719Z" }
|
|
1173
1173
|
wheels = [
|
|
1174
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
1174
|
+
{ url = "https://files.pythonhosted.org/packages/b3/b4/feb7015ae5f7870e8058ad713050f7fe3ddefa57aa7bdd4a83f2e3b9abb4/vmware_policy-1.21.0-py3-none-any.whl", hash = "sha256:a10c26816be09f9a2823cc58bc4eacb9b5eff8b6df49dfc5b504b3d76cb3b7ec", size = 99818, upload-time = "2026-10-15T10:13:31.67Z" },
|
|
1175
1175
|
]
|
|
1176
1176
|
|
|
1177
1177
|
[[package]]
|
|
1178
1178
|
name = "vmware-storage"
|
|
1179
|
-
version = "2.
|
|
1179
|
+
version = "2.2.0"
|
|
1180
1180
|
source = { editable = "." }
|
|
1181
1181
|
dependencies = [
|
|
1182
1182
|
{ name = "mcp", extra = ["cli"] },
|
|
@@ -1197,13 +1197,13 @@ dev = [
|
|
|
1197
1197
|
|
|
1198
1198
|
[package.metadata]
|
|
1199
1199
|
requires-dist = [
|
|
1200
|
-
{ name = "mcp", extras = ["cli"], specifier = ">=1.
|
|
1200
|
+
{ name = "mcp", extras = ["cli"], specifier = ">=1.28,<2.0" },
|
|
1201
1201
|
{ name = "pyaml", specifier = ">=24.0,<27.0" },
|
|
1202
1202
|
{ name = "python-dotenv", specifier = ">=1.0,<2.0" },
|
|
1203
1203
|
{ name = "pyvmomi", specifier = ">=8.0.3.0,<10.0" },
|
|
1204
1204
|
{ name = "rich", specifier = ">=13.0,<15.0" },
|
|
1205
1205
|
{ name = "typer", specifier = ">=0.12,<1.0" },
|
|
1206
|
-
{ name = "vmware-policy", specifier = ">=1.
|
|
1206
|
+
{ name = "vmware-policy", specifier = ">=1.21.0,<2.0" },
|
|
1207
1207
|
]
|
|
1208
1208
|
|
|
1209
1209
|
[package.metadata.requires-dev]
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
from typing import Optional
|
|
5
6
|
import functools
|
|
6
7
|
import json
|
|
7
8
|
import ssl
|
|
@@ -417,7 +418,7 @@ def iscsi_rescan(
|
|
|
417
418
|
result = rescan_storage(si, host_name)
|
|
418
419
|
_audit.log(
|
|
419
420
|
target=target or "default",
|
|
420
|
-
operation="
|
|
421
|
+
operation="rescan_storage",
|
|
421
422
|
resource=host_name,
|
|
422
423
|
parameters={"host_name": host_name},
|
|
423
424
|
result=result,
|
|
@@ -569,13 +570,43 @@ def doctor(
|
|
|
569
570
|
@app.command("mcp")
|
|
570
571
|
@handle_cli_errors
|
|
571
572
|
@cli_local("starts the MCP server; its tools audit themselves")
|
|
572
|
-
def mcp_cmd(
|
|
573
|
-
|
|
573
|
+
def mcp_cmd(
|
|
574
|
+
expose: Optional[str] = typer.Option(
|
|
575
|
+
None,
|
|
576
|
+
"--expose",
|
|
577
|
+
help="Which tools to offer: all (default) or read. Limits what clients see; "
|
|
578
|
+
"not authorization: the account's permissions still decide.",
|
|
579
|
+
),
|
|
580
|
+
allow_write: Optional[str] = typer.Option(
|
|
581
|
+
None,
|
|
582
|
+
"--allow-write",
|
|
583
|
+
help="With --expose read: comma-separated write tools to offer as well.",
|
|
584
|
+
),
|
|
585
|
+
transport: Optional[str] = typer.Option(
|
|
586
|
+
None,
|
|
587
|
+
"--transport",
|
|
588
|
+
help="stdio (default), https, or http (loopback only, behind a TLS reverse proxy). "
|
|
589
|
+
"https/http need a token: 'vmware-audit token create NAME'.",
|
|
590
|
+
),
|
|
591
|
+
host: Optional[str] = typer.Option(None, "--host", help="Bind address (default 127.0.0.1)."),
|
|
592
|
+
port: Optional[int] = typer.Option(None, "--port", help="Port (default 8443)."),
|
|
593
|
+
cert: Optional[str] = typer.Option(None, "--cert", help="TLS certificate (PEM) for https."),
|
|
594
|
+
key: Optional[str] = typer.Option(None, "--key", help="TLS private key (PEM) for https."),
|
|
595
|
+
public_name: Optional[str] = typer.Option(
|
|
596
|
+
None,
|
|
597
|
+
"--public-name",
|
|
598
|
+
help="Host names clients use, comma-separated; other Host/Origin values are refused.",
|
|
599
|
+
),
|
|
600
|
+
token_file: Optional[str] = typer.Option(
|
|
601
|
+
None, "--token-file", help="Token hash file (default $OPS_HOME/mcp-tokens)."
|
|
602
|
+
),
|
|
603
|
+
) -> None:
|
|
604
|
+
"""Start the MCP server (stdio by default; --transport https serves the network).
|
|
574
605
|
|
|
575
606
|
Single-command entry point for MCP clients:
|
|
576
607
|
vmware-storage mcp
|
|
577
608
|
|
|
578
|
-
Equivalent to the legacy `vmware-storage-mcp` console script.
|
|
609
|
+
Equivalent to the legacy `vmware-storage-mcp` console script for stdio (the console script takes no flags).
|
|
579
610
|
"""
|
|
580
611
|
import sys
|
|
581
612
|
|
|
@@ -592,4 +623,7 @@ def mcp_cmd() -> None:
|
|
|
592
623
|
|
|
593
624
|
from vmware_storage.mcp_server.server import main as _mcp_main
|
|
594
625
|
|
|
595
|
-
_mcp_main(
|
|
626
|
+
_mcp_main(
|
|
627
|
+
expose=expose, allow_write=allow_write, transport=transport, host=host, port=port,
|
|
628
|
+
cert=cert, key=key, public_name=public_name, token_file=token_file,
|
|
629
|
+
)
|
|
@@ -686,7 +686,7 @@ def rescan_storage(
|
|
|
686
686
|
return _preview(radius, decision)
|
|
687
687
|
_gate.refuse_if_blocked("rescan_storage", host_name, radius)
|
|
688
688
|
result = _ops_rescan_storage(si, host_name)
|
|
689
|
-
_safe_audit(target=target or "default", operation="
|
|
689
|
+
_safe_audit(target=target or "default", operation="rescan_storage",
|
|
690
690
|
resource=host_name, parameters={"host_name": host_name}, result=result)
|
|
691
691
|
return _with_note(
|
|
692
692
|
{"action": "rescanned", "result": result, "blast_radius": radius}, decision
|
|
@@ -994,10 +994,26 @@ def _exit_on_stop_signals() -> None:
|
|
|
994
994
|
signal.signal(sig, _stop)
|
|
995
995
|
|
|
996
996
|
|
|
997
|
-
def main(
|
|
997
|
+
def main(
|
|
998
|
+
expose: Optional[str] = None,
|
|
999
|
+
allow_write: Optional[str] = None,
|
|
1000
|
+
transport: Optional[str] = None,
|
|
1001
|
+
host: Optional[str] = None,
|
|
1002
|
+
port: Optional[int] = None,
|
|
1003
|
+
cert: Optional[str] = None,
|
|
1004
|
+
key: Optional[str] = None,
|
|
1005
|
+
public_name: Optional[str] = None,
|
|
1006
|
+
token_file: Optional[str] = None,
|
|
1007
|
+
) -> None:
|
|
998
1008
|
"""Run the MCP server."""
|
|
999
1009
|
_exit_on_stop_signals()
|
|
1000
|
-
|
|
1010
|
+
from vmware_policy.serve import run_server
|
|
1011
|
+
run_server(
|
|
1012
|
+
mcp,
|
|
1013
|
+
skill="storage",
|
|
1014
|
+
expose=expose, allow_write=allow_write, transport=transport, host=host, port=port,
|
|
1015
|
+
cert=cert, key=key, public_name=public_name, token_file=token_file,
|
|
1016
|
+
)
|
|
1001
1017
|
|
|
1002
1018
|
# The docstrings above are the schema. `describe_tool_parameters` copies each
|
|
1003
1019
|
# `Args:` entry into the JSON schema an agent actually reads, and closes the
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{vmware_storage-2.0.0 → vmware_storage-2.2.0}/skills/vmware-storage/references/agent-guardrails.md
RENAMED
|
File without changes
|
{vmware_storage-2.0.0 → vmware_storage-2.2.0}/skills/vmware-storage/references/capabilities.md
RENAMED
|
File without changes
|
{vmware_storage-2.0.0 → vmware_storage-2.2.0}/skills/vmware-storage/references/cli-reference.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/capability/test_entity_reachability.py
RENAMED
|
File without changes
|
{vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/capability/test_error_actionability.py
RENAMED
|
File without changes
|
{vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/capability/test_tool_description_quality.py
RENAMED
|
File without changes
|
{vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/capability/test_tool_manifest_budget.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_capability_grader.py
RENAMED
|
File without changes
|
{vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_cli_writes_guarded.py
RENAMED
|
File without changes
|
{vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_credential_env_override.py
RENAMED
|
File without changes
|
{vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_datastore_list_renders.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_env_secret_obfuscation.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_inventory_scale_n1.py
RENAMED
|
File without changes
|
{vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_iscsi_unreachable_host.py
RENAMED
|
File without changes
|
{vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_release_blockers.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_session_probe_eviction.py
RENAMED
|
File without changes
|
{vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_storage_hardening_fixes.py
RENAMED
|
File without changes
|
{vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_storage_ops_behavior.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|