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.
Files changed (107) hide show
  1. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/.claude-plugin/plugin.json +1 -1
  2. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/.mcp.json +1 -1
  3. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/PKG-INFO +3 -3
  4. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/RELEASE_NOTES.md +36 -0
  5. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/openclaw.plugin.json +1 -1
  6. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/package.json +1 -1
  7. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/pyproject.toml +3 -3
  8. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/server.json +2 -2
  9. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/skills/vmware-storage/SKILL.md +2 -2
  10. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/skills/vmware-storage/references/setup-guide.md +30 -3
  11. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/capability/_family.py +9 -7
  12. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/uv.lock +6 -6
  13. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/vmware_storage/__init__.py +1 -1
  14. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/vmware_storage/cli.py +39 -5
  15. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/vmware_storage/mcp_server/server.py +19 -3
  16. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/.clawhubignore +0 -0
  17. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/.env.example +0 -0
  18. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/.gitignore +0 -0
  19. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/Dockerfile +0 -0
  20. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/LICENSE +0 -0
  21. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/README-CN.md +0 -0
  22. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/README.md +0 -0
  23. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/SECURITY.md +0 -0
  24. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/config.example.yaml +0 -0
  25. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/docker-compose.yml +0 -0
  26. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/examples/mcp-configs/README.md +0 -0
  27. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/examples/mcp-configs/claude-code.json +0 -0
  28. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/examples/mcp-configs/continue.yaml +0 -0
  29. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/examples/mcp-configs/cursor.json +0 -0
  30. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/examples/mcp-configs/goose.json +0 -0
  31. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/examples/mcp-configs/localcowork.json +0 -0
  32. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/examples/mcp-configs/mcp-agent.yaml +0 -0
  33. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/examples/mcp-configs/vscode-copilot.json +0 -0
  34. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/patterns/README.md +0 -0
  35. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/patterns/iscsi-target-stale-rescan.yaml +0 -0
  36. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/skills/vmware-storage/evals/evals.json +0 -0
  37. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/skills/vmware-storage/references/agent-guardrails.md +0 -0
  38. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/skills/vmware-storage/references/capabilities.md +0 -0
  39. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/skills/vmware-storage/references/cli-reference.md +0 -0
  40. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/smithery.yaml +0 -0
  41. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/__init__.py +0 -0
  42. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/conftest.py +0 -0
  43. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/__init__.py +0 -0
  44. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/capability/__init__.py +0 -0
  45. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/capability/_scores.json +0 -0
  46. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/capability/_scoring.py +0 -0
  47. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/capability/_skill.py +0 -0
  48. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/capability/conftest.py +0 -0
  49. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/capability/test_entity_reachability.py +0 -0
  50. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/capability/test_error_actionability.py +0 -0
  51. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/capability/test_tool_description_quality.py +0 -0
  52. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/capability/test_tool_manifest_budget.py +0 -0
  53. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/__init__.py +0 -0
  54. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_atexit_handlers_do_not_accumulate.py +0 -0
  55. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_audit_isolation.py +0 -0
  56. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_cached_loader_agrees_with_the_resolver.py +0 -0
  57. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_capability_grader.py +0 -0
  58. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_cli_writes_guarded.py +0 -0
  59. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_credential_env_override.py +0 -0
  60. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_datastore_list_renders.py +0 -0
  61. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_doctor_authenticates_every_target.py +0 -0
  62. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_doctor_uses_the_config_the_tools_use.py +0 -0
  63. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_env_secret_obfuscation.py +0 -0
  64. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_fc_multipath.py +0 -0
  65. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_instructions_name_targets.py +0 -0
  66. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_inventory_scale_n1.py +0 -0
  67. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_iscsi_unreachable_host.py +0 -0
  68. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_release_blockers.py +0 -0
  69. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_remedy_survives_a_long_home.py +0 -0
  70. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_result_envelope.py +0 -0
  71. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_returned_failure_is_audited.py +0 -0
  72. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_session_probe_eviction.py +0 -0
  73. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_storage_hardening_fixes.py +0 -0
  74. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_storage_ops_behavior.py +0 -0
  75. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_tool_names_2_0.py +0 -0
  76. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_vim_attribute_conformance.py +0 -0
  77. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_vsan_efficiency.py +0 -0
  78. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_vsan_health_is_actually_queried.py +0 -0
  79. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/regression/test_vsan_reports_what_it_could_not_read.py +0 -0
  80. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/spec/__init__.py +0 -0
  81. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/spec/vsan_efficiency_endpoints.py +0 -0
  82. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/eval/spec/vsan_health_endpoints.py +0 -0
  83. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/test_init_and_onboarding.py +0 -0
  84. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/test_iscsi_gate.py +0 -0
  85. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/test_no_destructive_ops.py +0 -0
  86. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/test_no_destructive_vm_code.py +0 -0
  87. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/test_safe_error_passthrough.py +0 -0
  88. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/tests/test_stop_signal_runs_atexit.py +0 -0
  89. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/vmware_storage/config.py +0 -0
  90. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/vmware_storage/connection.py +0 -0
  91. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/vmware_storage/doctor.py +0 -0
  92. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/vmware_storage/init_wizard.py +0 -0
  93. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/vmware_storage/mcp_server/__init__.py +0 -0
  94. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/vmware_storage/mcp_server/__main__.py +0 -0
  95. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/vmware_storage/notify/__init__.py +0 -0
  96. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/vmware_storage/notify/audit.py +0 -0
  97. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/vmware_storage/ops/__init__.py +0 -0
  98. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/vmware_storage/ops/datastore_browser.py +0 -0
  99. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/vmware_storage/ops/inventory.py +0 -0
  100. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/vmware_storage/ops/iscsi_config.py +0 -0
  101. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/vmware_storage/ops/iscsi_gate.py +0 -0
  102. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/vmware_storage/ops/multipath.py +0 -0
  103. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/vmware_storage/ops/storage_paths.py +0 -0
  104. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/vmware_storage/ops/vsan.py +0 -0
  105. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/vmware_storage/ops/vsan_efficiency.py +0 -0
  106. {vmware_storage-2.0.0 → vmware_storage-2.2.0}/vmware_storage/ops/vsan_sdk.py +0 -0
  107. {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.0.0",
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",
@@ -5,7 +5,7 @@
5
5
  "command": "uvx",
6
6
  "args": [
7
7
  "--from",
8
- "vmware-storage==2.0.0",
8
+ "vmware-storage==2.2.0",
9
9
  "vmware-storage-mcp"
10
10
  ]
11
11
  }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: vmware-storage
3
- Version: 2.0.0
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.10
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.18.0
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
@@ -11,7 +11,7 @@
11
11
  "command": "uvx",
12
12
  "args": [
13
13
  "--from",
14
- "vmware-storage==2.0.0",
14
+ "vmware-storage==2.2.0",
15
15
  "vmware-storage-mcp"
16
16
  ]
17
17
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zw008/vmware-storage",
3
- "version": "2.0.0",
3
+ "version": "2.2.0",
4
4
  "description": "VMware vSphere storage with 14 MCP tools: datastores, iSCSI, vSAN, FC multipath.",
5
5
  "private": true,
6
6
  "license": "MIT",
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "vmware-storage"
7
- version = "2.0.0"
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.10,<2.0",
20
- "vmware-policy>=1.18.0,<2.0",
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.0.0",
10
+ "version": "2.2.0",
11
11
  "packages": [
12
12
  {
13
13
  "registryType": "pypi",
14
14
  "identifier": "vmware-storage",
15
- "version": "2.0.0",
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.0.0
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.0.0
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
@@ -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.0.0
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.0.0
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.0.0 https://github.com/vmware-skills/VMware-Storage.git
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', 'design_workflow',
108
- 'get_skill_catalog', 'get_workflow_status', 'list_workflows', 'plan_workflow',
109
- 'review_workflow', 'rollback', 'run_workflow', 'update_draft',
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
- 'get_supervisor_kubeconfig', 'get_supervisor_status', 'get_tkc_available_versions',
122
- 'get_tkc_cluster', 'get_tkc_kubeconfig', 'list_namespace_storage_usage',
123
- 'list_namespaces', 'list_supervisor_storage_policies', 'list_tkc_clusters',
124
- 'list_vm_classes', 'list_vm_service_groups', 'list_vm_service_network_interfaces',
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.18.2"
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/ce/a4f31330f983f411051ab0f42dcbd3c7174670541fa5cdb7faaf22991b24/vmware_policy-1.18.2.tar.gz", hash = "sha256:8e52629bf4a0d355a6841f1d9d5fb4ac1e69bbc7ae22d3843dd7cf3426b30e4c", size = 208412, upload-time = "2026-10-14T06:08:54.124Z" }
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/6b/cc/0ad37c57ee902819efc1c193b363df9a7c762794e7dff3318577c17743de/vmware_policy-1.18.2-py3-none-any.whl", hash = "sha256:6e7414f6cc7d783f486db858fd99dd7123ddefc0e823a8b319756e17ece03455", size = 80791, upload-time = "2026-10-14T06:08:52.267Z" },
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.0.0"
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.10,<2.0" },
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.18.0,<2.0" },
1206
+ { name = "vmware-policy", specifier = ">=1.21.0,<2.0" },
1207
1207
  ]
1208
1208
 
1209
1209
  [package.metadata.requires-dev]
@@ -1,3 +1,3 @@
1
1
  """VMware Storage — vSphere datastore, iSCSI, and vSAN management."""
2
2
 
3
- __version__ = "2.0.0"
3
+ __version__ = "2.2.0"
@@ -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="storage_rescan",
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() -> None:
573
- """Start the MCP server (stdio transport).
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="storage_rescan",
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
- mcp.run(transport="stdio")
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