Skip to content

feat: field-test fixes — vDNS flag, partial updates, kubeconfig envelope + generate tool, force delete#38

Merged
vks-team merged 4 commits into
mainfrom
fix/field-test-issues
Jul 14, 2026
Merged

feat: field-test fixes — vDNS flag, partial updates, kubeconfig envelope + generate tool, force delete#38
vks-team merged 4 commits into
mainfrom
fix/field-test-issues

Conversation

@vks-team

Copy link
Copy Markdown
Contributor

What

Nine items from a field-testing session, fixed one by one on this branch, each verified against the live API.

API-change fixes (things that broke)

  • configure_auto_upgrade crash — VKS answers several writes with 202 + empty body; mcp_core.http.BaseClient called resp.json() unconditionally → Expecting value: line 1 column 1. Empty success bodies now return None (mcp-core), and five handler messages no longer trail "None"/"null". (touches mcp-core → dual release)
  • list_k8s_resources / get_cluster_kubeconfig broke (Expected key current-context) — the kubeconfig endpoint now wraps the YAML in a JSON envelope {kubeConfig, status, ...}. New kubeconfig.py extracts it (legacy bare YAML still accepted), wired into both K8sClientCache and the tool — which had been returning the raw envelope to users.
  • update_cluster — the API no longer requires version/whitelistNodeCIDRs: the DTO is now a true partial update (all optional; empty body rejected at the handler with the valid-field list).

New capabilities (CLI parity)

  • generate_kubeconfig (write): a new cluster has no kubeconfig until one is mintedPOST .../kubeconfig {expirationDays} (default 30), asynchronous; the get-before-generate error teaches the flow. generate_ is read-only by convention elsewhere, so this is an explicit EXTRA_WRITE exception (named after the CLI command).
  • delete_nodegroup.force_deleteforceDelete=true (CLI --force-delete), documented as an escalation after a stuck/failed delete, user-confirmed first. The CLI's client-side --force (skip prompt) is deliberately not mapped — that role belongs to the confirm gate.

Product-rule fixes in discovery/guides

  • list_vpcs.enabled_dns (vServer dnsStatus) — azStrategy=MULTI clusters require a vDNS-enabled VPC; the creation guide filters and stops with console guidance when none qualify.
  • enabledServiceEndpoint is private-cluster-only with default true — the guide had the wrong field name (enabledServiceEndpointPlugin) and wrong default; the DTO field is now Optional and omitted from the wire body unless set.
  • delete_cluster_dryrun under-reported — it fetched one page of node groups (VKS enforces pageSize=10), so a cluster with >10 node groups showed an incomplete deletion preview. It now pages through.

Docs

READMEs/CLAUDE.md synced: 40 tools, cluster 13, partial update, enabled_dns, force_delete, kubeconfig-envelope + empty-202 quirks.

Tests

vks-mcp-server 264, mcp-core 15, repo conventions green; 18 files, +425/−60. Live-verified: vDNS flags match the console, auto-upgrade configure/delete round-trip, kubeconfig YAML + 9 pods listed in kube-system, generate flow on a CREATING cluster (actionable errors).

tytv2 added 2 commits July 14, 2026 11:20
…ope + generate tool, force delete

Nine items from a field-testing session, each verified against the live API:

- list_vpcs: VpcItem carries enabled_dns (vServer dnsStatus) — clusters
  with azStrategy=MULTI can only use a vDNS-enabled VPC; the creation
  guide filters accordingly and stops with console guidance when none
  qualify.
- update_cluster: the API no longer requires version/whitelistNodeCIDRs
  — UpdateClusterDto is now a true partial update (all fields optional,
  empty bodies rejected at the handler with the valid-field list).
- configure_auto_upgrade crashed with "Expecting value: line 1 column 0"
  — VKS answers several writes with 202 and an EMPTY body while
  mcp_core BaseClient called resp.json() unconditionally. Empty success
  bodies now return None; five handler messages no longer trail
  "None"/"null".
- list_k8s_resources / get_cluster_kubeconfig broke ("Expected key
  current-context") — the kubeconfig endpoint now wraps the YAML in a
  JSON envelope {kubeConfig, status, ...}. New kubeconfig.py extracts
  the YAML (legacy bare-YAML accepted), wired into both K8sClientCache
  and the tool; a not-ready cluster gets an actionable error.
- generate_kubeconfig (new write tool, CLI generate-kubeconfig parity):
  a new cluster has NO kubeconfig until one is minted — POST
  .../kubeconfig {expirationDays, default 30}, asynchronous; the
  get-before-generate error teaches the flow. Conventions: generate_
  prefix is read-only elsewhere, so this tool is an explicit EXTRA_WRITE
  exception (named after the CLI command).
- delete_nodegroup: force_delete param -> forceDelete=true (CLI
  --force-delete parity), documented as an escalation after a stuck or
  failed normal delete, user-confirmed. The CLI's client-side --force
  (skip prompt) is deliberately NOT mapped — that role belongs to the
  confirm gate.
- enabledServiceEndpoint is private-cluster-only, default TRUE there:
  the guide asked about the wrong field name (enabledServiceEndpointPlugin)
  with the wrong default; the DTO field is now Optional and omitted from
  the wire body unless set (public clusters never carry it).
- delete_cluster_dryrun listed at most one page of node groups (VKS
  enforces pageSize=10) — the deletion preview now pages through, so it
  can never under-report what will be destroyed.
- Docs synced: 40 tools, cluster 13, partial update, enabled_dns,
  force_delete, kubeconfig-envelope + empty-202 quirks, kubeconfig.py.
The kubeconfig carries a cluster-admin certificate + private key, yet
the tool was a plain read — any read-only session could exfiltrate
full-admin credentials into the conversation. Same gate as Kubernetes
Secrets/logs now (K8sHandler pattern: registered, runtime-denied with
an actionable error).

- ClusterHandler takes allow_sensitive_data_access; main() passes the
  CLI flag through.
- Docstring ## Requirements, SERVER_INSTRUCTIONS tool line, runtime-mode
  addendum, getting-started prompt, and README all state the gate.
- Note: the K8s tools are unaffected — K8sClientCache uses the
  kubeconfig internally without exposing it to the conversation.
@vks-team

Copy link
Copy Markdown
Contributor Author

Added a second commit: security fix (High)get_cluster_kubeconfig was a plain read while the kubeconfig carries cluster-admin credentials (cert + private key). It is now gated behind --allow-sensitive-data-access, same as Kubernetes Secrets/logs (runtime denial with an actionable error; K8s tools unaffected — the client cache uses the kubeconfig internally without exposing it). Verified live in both modes; 266 tests green.

…F-02)

The empty-body guard in mcp_core.http (earlier commit in this PR)
already fixes both auto-upgrade tools; F-02 reproduced on v0.8.0, which
predates it. This adds the missing regression test for the DELETE path
so both tools named in the report are covered.
@vks-team

Copy link
Copy Markdown
Contributor Author

Bug report F-02 (configure/delete_auto_upgrade error despite success) is fixed by this PR — the report reproduces on v0.8.0, which predates the fix.

  • Root cause matches the report exactly: mcp_core.http.BaseClient._request called resp.json() unconditionally after the is_success gate; the two auto-upgrade endpoints answer 2xx with an empty body.
  • Fix (commit c696a13): empty/whitespace success bodies return None (slightly stronger than the proposed resp.json() if resp.content else None — also covers whitespace-only bodies); handler messages no longer trail "None".
  • This commit adds the missing regression test for the delete_auto_upgrade path, so both tools named in F-02 are covered. Live-verified earlier: configure → delete round-trip succeeds against the real API.

…s match on

Model-eval finding: "bật auto-healing cho cluster X" sent 3/6 models to
get_cluster first — the one-line description ("Configure auto-healing
for a VKS cluster") never said the tool both ENABLES and DISABLES
healing, nor what it tunes.

- configure_auto_healing: "Enable, disable, or tune..." + the three
  tuning knobs (maxUnhealthy, unhealthyRange, timeoutUnhealthy) + a
  read-vs-write pointer (get_cluster to only READ the config).
- configure_auto_upgrade: enabling = setting the weekly schedule;
  turning OFF is delete_auto_upgrade (cross-ref); reading is
  get_cluster.
- delete_auto_upgrade: framed as "turn OFF auto-upgrade", counterpart
  of configure_auto_upgrade.

A conventions test pins the intent words, tuning params, and cross-refs.
@vks-team
vks-team merged commit 7713736 into main Jul 14, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant