vmware-avi 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_avi-2.0.0 → vmware_avi-2.2.0}/.claude-plugin/plugin.json +1 -1
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/.mcp.json +1 -1
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/PKG-INFO +3 -3
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/RELEASE_NOTES.md +36 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/openclaw.plugin.json +1 -1
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/package.json +1 -1
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/pyproject.toml +3 -3
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/server.json +2 -2
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/skills/vmware-avi/SKILL.md +2 -2
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/skills/vmware-avi/references/capabilities.md +1 -1
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/skills/vmware-avi/references/setup-guide.md +31 -4
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/tests/eval/capability/_family.py +9 -7
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/uv.lock +6 -6
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/vmware_avi/__init__.py +1 -1
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/vmware_avi/cli.py +38 -4
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/vmware_avi/mcp_server/server.py +18 -2
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/.clawhubignore +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/.env.example +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/.gitattributes +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/.gitignore +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/Dockerfile +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/README-CN.md +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/README.md +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/SECURITY.md +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/config.example.yaml +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/evals/evals.json +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/examples/mcp-configs/claude-code.json +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/examples/mcp-configs/cursor.json +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/skills/vmware-avi/references/agent-guardrails.md +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/skills/vmware-avi/references/cli-reference.md +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/smithery.yaml +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/tests/__init__.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/tests/conftest.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/tests/eval/__init__.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/tests/eval/capability/__init__.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/tests/eval/capability/_scores.json +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/tests/eval/capability/_scoring.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/tests/eval/capability/_skill.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/tests/eval/capability/conftest.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/tests/eval/capability/test_entity_reachability.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/tests/eval/capability/test_error_actionability.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/tests/eval/capability/test_tool_description_quality.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/tests/eval/capability/test_tool_manifest_budget.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/tests/eval/regression/__init__.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/tests/eval/regression/test_ako_diff_predicts_upgrade.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/tests/eval/regression/test_avi_specific.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/tests/eval/regression/test_capability_grader.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/tests/eval/regression/test_cli_writes_guarded.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/tests/eval/regression/test_config_path_resolution_is_shared.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/tests/eval/regression/test_env_secret_obfuscation.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/tests/eval/regression/test_every_tool_parameter_is_documented.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/tests/eval/regression/test_external_text_sanitized.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/tests/eval/regression/test_fix_pack.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/tests/eval/regression/test_helm_output_display_is_redacted.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/tests/eval/regression/test_helm_values_redaction.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/tests/eval/regression/test_init_and_onboarding.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/tests/eval/regression/test_instructions_name_targets.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/tests/eval/regression/test_list_scaling.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/tests/eval/regression/test_release_blockers.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/tests/eval/regression/test_text_io_declares_encoding.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/tests/eval/regression/test_write_command_teaching.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/tests/test_ako_pod.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/tests/test_ako_sync.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/tests/test_ako_write_gate.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/tests/test_analytics.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/tests/test_audit.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/tests/test_config.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/tests/test_error_logs.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/tests/test_lb_write_gate.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/tests/test_mcp_error_paths.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/tests/test_mcp_tools.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/tests/test_no_destructive_ops.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/tests/test_pool_mgmt.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/tests/test_safe_error_passthrough.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/tests/test_se_mgmt.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/tests/test_vs_mgmt.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/vmware_avi/_errors.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/vmware_avi/_safety.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/vmware_avi/config.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/vmware_avi/connection.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/vmware_avi/doctor.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/vmware_avi/init_wizard.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/vmware_avi/k8s_connection.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/vmware_avi/mcp_server/__init__.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/vmware_avi/mcp_server/__main__.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/vmware_avi/notify/__init__.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/vmware_avi/notify/audit.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/vmware_avi/ops/__init__.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/vmware_avi/ops/ako_config.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/vmware_avi/ops/ako_gate.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/vmware_avi/ops/ako_ingress.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/vmware_avi/ops/ako_multi_cluster.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/vmware_avi/ops/ako_pod.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/vmware_avi/ops/ako_sync.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/vmware_avi/ops/analytics.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/vmware_avi/ops/lb_gate.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/vmware_avi/ops/pool_mgmt.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/vmware_avi/ops/se_mgmt.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/vmware_avi/ops/ssl_mgmt.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/vmware_avi/ops/vs_mgmt.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/vmware_avi/ops/write_gate.py +0 -0
- {vmware_avi-2.0.0 → vmware_avi-2.2.0}/vmware_avi/policy_environment.py +0 -0
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://anthropic.com/claude-code/plugin.schema.json",
|
|
3
3
|
"name": "vmware-avi",
|
|
4
4
|
"displayName": "VMware AVI",
|
|
5
|
-
"version": "2.
|
|
5
|
+
"version": "2.2.0",
|
|
6
6
|
"description": "VMware AVI (NSX ALB) load balancer plus AKO Kubernetes ops — 28 MCP tools.",
|
|
7
7
|
"author": {
|
|
8
8
|
"name": "Wei Zhou",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: vmware-avi
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.2.0
|
|
4
4
|
Summary: AVI (NSX Advanced Load Balancer) management and AKO Kubernetes operations tool
|
|
5
5
|
Project-URL: Homepage, https://github.com/vmware-skills/VMware-AVI
|
|
6
6
|
Project-URL: Repository, https://github.com/vmware-skills/VMware-AVI
|
|
@@ -12,12 +12,12 @@ Requires-Python: >=3.10
|
|
|
12
12
|
Requires-Dist: avisdk<31.0,>=22.1
|
|
13
13
|
Requires-Dist: httpx<1.0,>=0.27
|
|
14
14
|
Requires-Dist: kubernetes<33.0,>=28.0
|
|
15
|
-
Requires-Dist: mcp[cli]<2.0,>=1.
|
|
15
|
+
Requires-Dist: mcp[cli]<2.0,>=1.28
|
|
16
16
|
Requires-Dist: pyaml<27.0,>=24.0
|
|
17
17
|
Requires-Dist: python-dotenv<2.0,>=1.0
|
|
18
18
|
Requires-Dist: rich<15.0,>=13.0
|
|
19
19
|
Requires-Dist: typer<1.0,>=0.12
|
|
20
|
-
Requires-Dist: vmware-policy<2.0,>=1.
|
|
20
|
+
Requires-Dist: vmware-policy<2.0,>=1.21.0
|
|
21
21
|
Description-Content-Type: text/markdown
|
|
22
22
|
|
|
23
23
|
<!-- mcp-name: io.github.vmware-skills/vmware-avi -->
|
|
@@ -1,3 +1,39 @@
|
|
|
1
|
+
## v2.2.0 — serve MCP over HTTPS
|
|
2
|
+
|
|
3
|
+
`vmware-avi 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-avi 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-avi-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-avi 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-avi mcp --expose read --allow-write disable_lb_pool_member
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
* `--expose read` (or `VMWARE_AVI_MCP_EXPOSE=read`) keeps only tools annotated `readOnlyHint: true`; `--allow-write a,b`
|
|
29
|
+
(or `VMWARE_AVI_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
|
Every MCP tool in the VMware skill family now follows one naming convention: the verb comes first
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "vmware-avi"
|
|
7
|
-
version = "2.
|
|
7
|
+
version = "2.2.0"
|
|
8
8
|
description = "AVI (NSX Advanced Load Balancer) management and AKO Kubernetes operations tool"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
@@ -18,8 +18,8 @@ dependencies = [
|
|
|
18
18
|
"rich>=13.0,<15.0",
|
|
19
19
|
"httpx>=0.27,<1.0",
|
|
20
20
|
"python-dotenv>=1.0,<2.0",
|
|
21
|
-
"mcp[cli]>=1.
|
|
22
|
-
"vmware-policy>=1.
|
|
21
|
+
"mcp[cli]>=1.28,<2.0",
|
|
22
|
+
"vmware-policy>=1.21.0,<2.0",
|
|
23
23
|
]
|
|
24
24
|
|
|
25
25
|
|
|
@@ -7,12 +7,12 @@
|
|
|
7
7
|
"url": "https://github.com/vmware-skills/VMware-AVI",
|
|
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-avi",
|
|
15
|
-
"version": "2.
|
|
15
|
+
"version": "2.2.0",
|
|
16
16
|
"runtimeHint": "uvx",
|
|
17
17
|
"packageArguments": [
|
|
18
18
|
{
|
|
@@ -53,7 +53,7 @@ AVI (NSX Advanced Load Balancer) application delivery and AKO Kubernetes operati
|
|
|
53
53
|
## Quick Install
|
|
54
54
|
|
|
55
55
|
```bash
|
|
56
|
-
uv tool install vmware-avi==2.
|
|
56
|
+
uv tool install vmware-avi==2.2.0
|
|
57
57
|
vmware-avi doctor # checks Controller connectivity + kubeconfig + avisdk
|
|
58
58
|
```
|
|
59
59
|
|
|
@@ -235,7 +235,7 @@ Force resync triggers AKO to re-reconcile all K8s objects. If the drift persists
|
|
|
235
235
|
## Setup
|
|
236
236
|
|
|
237
237
|
```bash
|
|
238
|
-
uv tool install vmware-avi==2.
|
|
238
|
+
uv tool install vmware-avi==2.2.0
|
|
239
239
|
mkdir -p ~/.vmware-avi
|
|
240
240
|
vmware-avi init # generates config.yaml and .env templates
|
|
241
241
|
chmod 600 ~/.vmware-avi/.env
|
|
@@ -37,7 +37,7 @@ All 28 MCP tools exposed by `vmware-avi mcp` (v1.5.15+; legacy entry point: `vmw
|
|
|
37
37
|
| `vmware-avi mcp` (CLI subcommand, stdio) | ✅ Full | ✅ v1.5.15+ default — no PyPI re-resolve, works behind corporate TLS proxies. |
|
|
38
38
|
| `vmware-avi-mcp` (legacy console script, stdio) | ✅ Full | Kept for backward compatibility with pre-1.5.15 configs. |
|
|
39
39
|
| `python -m vmware_avi.mcp_server` (stdio, via `__main__.py`) | ✅ Full | Docker image `CMD` only — not for end-user CLI install, and no longer used by `smithery.yaml` (which now calls the `vmware-avi mcp` entry point). Added v1.5.22. |
|
|
40
|
-
| `uvx --from vmware-avi==2.
|
|
40
|
+
| `uvx --from vmware-avi==2.2.0 vmware-avi-mcp` | ⚠ Fallback | Re-resolves PyPI on each launch; fails behind corporate TLS proxies (踩坑 #25). Use `UV_NATIVE_TLS=true` workaround. |
|
|
41
41
|
|
|
42
42
|
## Automation Level Reference
|
|
43
43
|
|
|
@@ -21,7 +21,7 @@ Complete installation, configuration, and AI platform integration guide for the
|
|
|
21
21
|
### Standard Install (recommended)
|
|
22
22
|
|
|
23
23
|
```bash
|
|
24
|
-
uv tool install vmware-avi==2.
|
|
24
|
+
uv tool install vmware-avi==2.2.0
|
|
25
25
|
```
|
|
26
26
|
|
|
27
27
|
This installs the CLI (`vmware-avi`, with `vmware-avi mcp` subcommand for the MCP server in v1.5.15+), the legacy `vmware-avi-mcp` entry point (for backward compatibility), and all Python dependencies in an isolated environment.
|
|
@@ -29,7 +29,7 @@ This installs the CLI (`vmware-avi`, with `vmware-avi mcp` subcommand for the MC
|
|
|
29
29
|
### Development Install
|
|
30
30
|
|
|
31
31
|
```bash
|
|
32
|
-
git clone --branch v2.
|
|
32
|
+
git clone --branch v2.2.0 https://github.com/vmware-skills/VMware-AVI.git
|
|
33
33
|
cd VMware-AVI
|
|
34
34
|
uv pip install -e ".[dev]"
|
|
35
35
|
```
|
|
@@ -43,7 +43,7 @@ For platforms that prefer containerized MCP servers (e.g., Smithery registry, Ku
|
|
|
43
43
|
Build and run the MCP server in a container. The image uses `python:3.12-slim` with `uv` for dependency installation and runs `python -m vmware_avi.mcp_server` on stdio (no port exposed — MCP uses stdin/stdout).
|
|
44
44
|
|
|
45
45
|
```bash
|
|
46
|
-
git clone --branch v2.
|
|
46
|
+
git clone --branch v2.2.0 https://github.com/vmware-skills/VMware-AVI.git
|
|
47
47
|
cd VMware-AVI
|
|
48
48
|
|
|
49
49
|
# Build
|
|
@@ -72,7 +72,7 @@ Users can install via the Smithery UI or CLI without managing Python environment
|
|
|
72
72
|
|
|
73
73
|
| Deployment | Best For |
|
|
74
74
|
|------------|----------|
|
|
75
|
-
| `uv tool install vmware-avi==2.
|
|
75
|
+
| `uv tool install vmware-avi==2.2.0` + `vmware-avi mcp` | Local developer workstation, single-user CLI + MCP |
|
|
76
76
|
| Docker image | Self-hosted agents, CI runners, isolated environments, multi-user servers |
|
|
77
77
|
| Smithery | Zero-install agent integration, registry-managed discovery, hosted-MCP workflows |
|
|
78
78
|
|
|
@@ -212,6 +212,33 @@ whitespace are handled correctly).
|
|
|
212
212
|
> Secrets Manager, or a Kubernetes Secret) into the `*_PASSWORD` environment
|
|
213
213
|
> variable at process start. The code reads the env var either way.
|
|
214
214
|
|
|
215
|
+
## Limiting which tools are offered
|
|
216
|
+
|
|
217
|
+
By default the MCP server offers every tool. To offer only read tools, start it with `--expose read`, or set
|
|
218
|
+
`VMWARE_AVI_MCP_EXPOSE=read` in the MCP client's `env` block (useful when the client launches `vmware-avi mcp` itself). To offer
|
|
219
|
+
chosen write tools as well, add `--allow-write` with a comma-separated list (or `VMWARE_AVI_MCP_ALLOW_WRITE`):
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
vmware-avi mcp --expose read --allow-write disable_lb_pool_member
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
- A read tool is one annotated `readOnlyHint: true`; every other tool counts as a write.
|
|
226
|
+
- An unknown setting, or a name that is not a write tool of this server, stops the server before it serves (exit
|
|
227
|
+
code 2), so it never offers more than you asked for. Pre-2.0 tool names are accepted.
|
|
228
|
+
- With `--expose read`, the server prints one line to stderr saying what it exposes.
|
|
229
|
+
- Flags and environment variables are not mixed: if either flag is given, both environment variables are
|
|
230
|
+
ignored, so a leftover `_ALLOW_WRITE` in the shell cannot widen `--expose read`. A blank flag value counts as
|
|
231
|
+
not given.
|
|
232
|
+
- A tool that runs other steps (a plan, workflow or batch tool) carries every write it can execute, including
|
|
233
|
+
writes this setting hides. Expose such a tool only if you would expose those writes too.
|
|
234
|
+
- A launcher that imports the server object can call
|
|
235
|
+
`vmware_policy.exposure.restrict_tools(mcp, skill="avi", expose="read", allow_write=[...])` before running it,
|
|
236
|
+
instead of editing the SDK's tool registry.
|
|
237
|
+
- This limits what clients are offered. It is **not** authorization: whether a call may change anything is decided by
|
|
238
|
+
the account's permissions, and deny rules in `~/.vmware/rules.yaml` still apply to every exposed tool.
|
|
239
|
+
- An agent that can run shell commands can also reach the platform without MCP (SSH, curl, govc, PowerCLI). So
|
|
240
|
+
the service account itself must be least-privilege: exposure and deny rules are guardrails, not the boundary.
|
|
241
|
+
|
|
215
242
|
## Security
|
|
216
243
|
|
|
217
244
|
> **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", "NSX", and "AVI" 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
|
}),
|
|
@@ -1423,7 +1423,7 @@ wheels = [
|
|
|
1423
1423
|
|
|
1424
1424
|
[[package]]
|
|
1425
1425
|
name = "vmware-avi"
|
|
1426
|
-
version = "2.
|
|
1426
|
+
version = "2.2.0"
|
|
1427
1427
|
source = { editable = "." }
|
|
1428
1428
|
dependencies = [
|
|
1429
1429
|
{ name = "avisdk" },
|
|
@@ -1449,12 +1449,12 @@ requires-dist = [
|
|
|
1449
1449
|
{ name = "avisdk", specifier = ">=22.1,<31.0" },
|
|
1450
1450
|
{ name = "httpx", specifier = ">=0.27,<1.0" },
|
|
1451
1451
|
{ name = "kubernetes", specifier = ">=28.0,<33.0" },
|
|
1452
|
-
{ name = "mcp", extras = ["cli"], specifier = ">=1.
|
|
1452
|
+
{ name = "mcp", extras = ["cli"], specifier = ">=1.28,<2.0" },
|
|
1453
1453
|
{ name = "pyaml", specifier = ">=24.0,<27.0" },
|
|
1454
1454
|
{ name = "python-dotenv", specifier = ">=1.0,<2.0" },
|
|
1455
1455
|
{ name = "rich", specifier = ">=13.0,<15.0" },
|
|
1456
1456
|
{ name = "typer", specifier = ">=0.12,<1.0" },
|
|
1457
|
-
{ name = "vmware-policy", specifier = ">=1.
|
|
1457
|
+
{ name = "vmware-policy", specifier = ">=1.21.0,<2.0" },
|
|
1458
1458
|
]
|
|
1459
1459
|
|
|
1460
1460
|
[package.metadata.requires-dev]
|
|
@@ -1466,16 +1466,16 @@ dev = [
|
|
|
1466
1466
|
|
|
1467
1467
|
[[package]]
|
|
1468
1468
|
name = "vmware-policy"
|
|
1469
|
-
version = "1.
|
|
1469
|
+
version = "1.21.0"
|
|
1470
1470
|
source = { registry = "https://pypi.org/simple" }
|
|
1471
1471
|
dependencies = [
|
|
1472
1472
|
{ name = "pyyaml" },
|
|
1473
1473
|
{ name = "rich" },
|
|
1474
1474
|
{ name = "typer" },
|
|
1475
1475
|
]
|
|
1476
|
-
sdist = { url = "https://files.pythonhosted.org/packages/5d/
|
|
1476
|
+
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" }
|
|
1477
1477
|
wheels = [
|
|
1478
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
1478
|
+
{ 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" },
|
|
1479
1479
|
]
|
|
1480
1480
|
|
|
1481
1481
|
[[package]]
|
|
@@ -5,6 +5,7 @@ Typer-based CLI with subcommands for VS, Pool, SSL, SE, Analytics, and AKO opera
|
|
|
5
5
|
|
|
6
6
|
from __future__ import annotations
|
|
7
7
|
|
|
8
|
+
from typing import Optional
|
|
8
9
|
import sys
|
|
9
10
|
|
|
10
11
|
import typer
|
|
@@ -110,13 +111,43 @@ def doctor() -> None:
|
|
|
110
111
|
|
|
111
112
|
@app.command("mcp")
|
|
112
113
|
@cli_local("starts the MCP server; its tools audit themselves")
|
|
113
|
-
def mcp_cmd(
|
|
114
|
-
|
|
114
|
+
def mcp_cmd(
|
|
115
|
+
expose: Optional[str] = typer.Option(
|
|
116
|
+
None,
|
|
117
|
+
"--expose",
|
|
118
|
+
help="Which tools to offer: all (default) or read. Limits what clients see; "
|
|
119
|
+
"not authorization: the account's permissions still decide.",
|
|
120
|
+
),
|
|
121
|
+
allow_write: Optional[str] = typer.Option(
|
|
122
|
+
None,
|
|
123
|
+
"--allow-write",
|
|
124
|
+
help="With --expose read: comma-separated write tools to offer as well.",
|
|
125
|
+
),
|
|
126
|
+
transport: Optional[str] = typer.Option(
|
|
127
|
+
None,
|
|
128
|
+
"--transport",
|
|
129
|
+
help="stdio (default), https, or http (loopback only, behind a TLS reverse proxy). "
|
|
130
|
+
"https/http need a token: 'vmware-audit token create NAME'.",
|
|
131
|
+
),
|
|
132
|
+
host: Optional[str] = typer.Option(None, "--host", help="Bind address (default 127.0.0.1)."),
|
|
133
|
+
port: Optional[int] = typer.Option(None, "--port", help="Port (default 8443)."),
|
|
134
|
+
cert: Optional[str] = typer.Option(None, "--cert", help="TLS certificate (PEM) for https."),
|
|
135
|
+
key: Optional[str] = typer.Option(None, "--key", help="TLS private key (PEM) for https."),
|
|
136
|
+
public_name: Optional[str] = typer.Option(
|
|
137
|
+
None,
|
|
138
|
+
"--public-name",
|
|
139
|
+
help="Host names clients use, comma-separated; other Host/Origin values are refused.",
|
|
140
|
+
),
|
|
141
|
+
token_file: Optional[str] = typer.Option(
|
|
142
|
+
None, "--token-file", help="Token hash file (default $OPS_HOME/mcp-tokens)."
|
|
143
|
+
),
|
|
144
|
+
) -> None:
|
|
145
|
+
"""Start the MCP server (stdio by default; --transport https serves the network).
|
|
115
146
|
|
|
116
147
|
Single-command entry point for MCP clients:
|
|
117
148
|
vmware-avi mcp
|
|
118
149
|
|
|
119
|
-
Equivalent to the legacy `vmware-avi-mcp` console script.
|
|
150
|
+
Equivalent to the legacy `vmware-avi-mcp` console script for stdio (the console script takes no flags).
|
|
120
151
|
"""
|
|
121
152
|
import sys
|
|
122
153
|
|
|
@@ -134,7 +165,10 @@ def mcp_cmd() -> None:
|
|
|
134
165
|
|
|
135
166
|
from vmware_avi.mcp_server.server import main as _mcp_main
|
|
136
167
|
|
|
137
|
-
_mcp_main(
|
|
168
|
+
_mcp_main(
|
|
169
|
+
expose=expose, allow_write=allow_write, transport=transport, host=host, port=port,
|
|
170
|
+
cert=cert, key=key, public_name=public_name, token_file=token_file,
|
|
171
|
+
)
|
|
138
172
|
|
|
139
173
|
|
|
140
174
|
@app.command()
|
|
@@ -1146,10 +1146,26 @@ from vmware_avi.policy_environment import _cached_config, _environment_for # no
|
|
|
1146
1146
|
# ═══════════════════════════════════════════════════════════════════════════════
|
|
1147
1147
|
|
|
1148
1148
|
|
|
1149
|
-
def main(
|
|
1149
|
+
def main(
|
|
1150
|
+
expose: Optional[str] = None,
|
|
1151
|
+
allow_write: Optional[str] = None,
|
|
1152
|
+
transport: Optional[str] = None,
|
|
1153
|
+
host: Optional[str] = None,
|
|
1154
|
+
port: Optional[int] = None,
|
|
1155
|
+
cert: Optional[str] = None,
|
|
1156
|
+
key: Optional[str] = None,
|
|
1157
|
+
public_name: Optional[str] = None,
|
|
1158
|
+
token_file: Optional[str] = None,
|
|
1159
|
+
) -> None:
|
|
1150
1160
|
"""Entry point for vmware-avi-mcp."""
|
|
1151
1161
|
logging.basicConfig(level=logging.INFO)
|
|
1152
|
-
|
|
1162
|
+
from vmware_policy.serve import run_server
|
|
1163
|
+
run_server(
|
|
1164
|
+
mcp,
|
|
1165
|
+
skill="avi",
|
|
1166
|
+
expose=expose, allow_write=allow_write, transport=transport, host=host, port=port,
|
|
1167
|
+
cert=cert, key=key, public_name=public_name, token_file=token_file,
|
|
1168
|
+
)
|
|
1153
1169
|
|
|
1154
1170
|
|
|
1155
1171
|
if __name__ == "__main__":
|
|
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
|
{vmware_avi-2.0.0 → vmware_avi-2.2.0}/tests/eval/capability/test_tool_description_quality.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{vmware_avi-2.0.0 → vmware_avi-2.2.0}/tests/eval/regression/test_ako_diff_predicts_upgrade.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{vmware_avi-2.0.0 → vmware_avi-2.2.0}/tests/eval/regression/test_config_path_resolution_is_shared.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{vmware_avi-2.0.0 → vmware_avi-2.2.0}/tests/eval/regression/test_helm_output_display_is_redacted.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{vmware_avi-2.0.0 → vmware_avi-2.2.0}/tests/eval/regression/test_instructions_name_targets.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{vmware_avi-2.0.0 → vmware_avi-2.2.0}/tests/eval/regression/test_text_io_declares_encoding.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
|
|
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
|