Skip to content

Releases: vmware-skills/VMware-Log-Insight

v2.4.1 — fixed against a real 8.18.7 appliance (VMware-AIops#45)

Choose a tag to compare

@zw008 zw008 released this 17 Oct 14:29

First run of every tool on real hardware (Aria Operations for Logs 8.18.7-25423541, ingesting ESXi and vCenter
syslog). Three of the seven tools failed on every call, because the tests mocked response shapes the appliance
never sends. The regression tests now replay responses captured from that appliance
(tests/fixtures/li_8_18_7.json).

  • get_log_alert_history returns real records. Captured from a temporary alert that fired on 8.18.7 (then
    deleted): each record is {triggerTimestamp, acknowledged, messages, ...}. The code read keys a record does not
    have, so every row would have been {timestamp_ms: null, info: ""}. Rows are now {timestamp_ms, acknowledged, message_count, messages} (at most 3 events per record). History is paged by the appliance (up to 50), so a full page now
    says truncated: true with total: null instead of claiming to be the whole history.
  • list_log_fields, list_log_alerts, get_log_alert_history work. 8.18.7 answers these with a bare JSON
    array; the code read it as an object and every call failed with AttributeError: operation failed. Field items are
    now {name, internal_name, type}. For a content-pack field name is the qualified
    <pack namespace>:<display name>, the only form a query accepts (verified on 8.18.7). These fields also carry
    display_name and content_pack. This costs one extra read of the content-pack list.
  • aggregate_logs bins have timestamps. Bins carry minTimestamp/maxTimestamp; every timestamp_ms was
    null, so spikes could not be placed in time. Bins are now {timestamp_ms, end_ms, value}, oldest first.
  • aggregate_logs takes field (CLI --field). UCOUNT, AVG, MIN, MAX, SUM, STDDEV and VARIANCE need one and
    answered HTTP 400 without it; COUNT and SAMPLE refuse one. Both are now checked before the call. An unknown field
    returns an empty series with a note. A SAMPLE bin's value (a raw event) is now sanitized.
  • search_logs fills hostname, appname and procid. On 8.18.7 these carry a position in the event text
    instead of a value, and always came back as "".
  • search_logs returns at most 200 events and says when it lowers limit. The cap was 20000 and silent; 20000
    events was a 16 MB result that took 31 s and was stored whole in the audit database.
  • Windows longer than ~24.8 days work. The appliance reads LAST as a 32-bit millisecond count and answered
    HTTP 400; such a window is now sent as an absolute start time.
  • begin_ms after end_ms, and a value that looks like epoch seconds, are refused with the fix.
  • An alert id containing /, ?, spaces or .. is refused (../version used to reach /version). An unknown id
    (HTTP 404, or 500 for a non-UUID) now says "copy an exact id", not "retry".
  • Errors say "run doctor" only when doctor can help (config, credentials, reachability). An unexpected error says it
    is not an input problem.
  • doctor now reads GET /fields through the same code the tools use, so a broken query API no longer passes.
  • Roles: a target-limited role can use this skill. The role resolver read a name field that this skill's
    target config does not have, so it raised on every call. Every call by a token whose role lists targets was
    refused as "cannot be resolved", and the audit row could not name the default target.
  • A refused argument now logs one warning line; real failures keep their traceback.
  • Spikes are measured against quiet, not only against bursts. The appliance omits bins with no events. For
    COUNT and UCOUNT those bins are now added back as 0 (filled_empty_bins: true), so a burst after a quiet stretch
    is reported as a spike.
  • A content-pack field whose pack is missing from the pack list is marked unresolved with a note. Fields the
    appliance lists twice are listed once. A non-JSON answer (e.g. a proxy's login page) is reported as the
    appliance or proxy answering wrongly, not as an argument error.
  • An empty text search says why. text matches whole words: on 8.18.7 agt-w2 returned 0 events
    (complete: true) while agt-w2* returned 50+. When a text search without * matches nothing, search_logs and
    aggregate_logs now add a note suggesting the wildcard, instead of an empty result that reads as "no such logs".
  • Docs: search_logs has no field-filter parameter (the docs said it had); text matches whole words, not
    substrings, and * is a wildcard; corrected token estimates.

v2.4.0 — roles for network callers (HLD §18)

Choose a tag to compare

@zw008 zw008 released this 16 Oct 09:30
  • Declares the role metadata vmware-policy ≥ 1.24.0 needs to apply roles to this server over HTTPS
    (HLD §18): how a missing target resolves. With an older vmware-policy nothing changes. Once an operator runs
    vmware-audit roles enable, a token's role decides which tools and targets it may use here; a refused call is
    audited as denied. See vmware-policy's README, "Roles for network callers".
  • A target-limited role is checked against the same config the connection uses: the copy the server's connection manager loaded on its first connection. Edit config.yaml and restart for both to see the change.
  • README and setup guide: one endpoint for several people or roles.

v2.3.0 — calls on one target run side by side over HTTPS

Choose a tag to compare

@zw008 zw008 released this 15 Oct 16:19

When vmware-log-insight mcp serves the network (--transport https or http), calls no longer queue behind each other.
Calls that name the same target, or name no target, now run side by side instead of one at a time (HLD §16
D-13(2), via vmware-policy 1.22.0):

  • Each call gets its own session to the Log Insight for as long as it runs, so two calls never share a login.
  • Each target keeps up to VMWARE_MCP_POOL_SIZE sessions (default 2). Each session is a login on the target, so
    raise it only as far as the account's session limit allows.
  • A call that finds every session busy waits at most 300 s for one, then fails with a message saying so.
  • A session that has expired or stopped answering is closed and replaced the next time a call needs it.

stdio and the CLI are unchanged: one session per target, reused.

v2.2.0 — serve MCP over HTTPS

Choose a tag to compare

@zw008 zw008 released this 15 Oct 12:06

vmware-log-insight mcp can now serve the network as well as stdio (HLD §16, via vmware-policy 1.21.0):

vmware-audit token create alice          # once per caller; shown once
vmware-log-insight mcp --transport https --host 0.0.0.0 --port 8443 \
    --cert server.pem --key server-key.pem --public-name mcp.example.com

Connect a client and manage callers (Claude Code shown; any MCP client with streamable HTTP and custom headers works):

claude mcp add --transport http vmware-log-insight https://mcp.example.com:8443/mcp \
    --header "Authorization: Bearer $VMWARE_MCP_TOKEN"
vmware-audit token list                  # names only
vmware-audit token revoke alice          # refused from its next request, no restart
  • Every request needs Authorization: Bearer <token>; the server will not start without a token, refuses Host or
    Origin values outside --public-name, and checks itself (unauthenticated requests must get 401) before it
    binds. --transport http binds loopback only, for a TLS-terminating reverse proxy.
  • Audit rows record the caller as token:<name> and the surface as mcp-https. Calls naming different targets
    run in parallel; calls naming no target run one at a time.
  • stdio remains the default; the vmware-log-insight-mcp console script and python -m are unchanged.
  • Everyone who can reach the endpoint acts with this server's account; run one endpoint per privilege level.
  • Requires vmware-policy>=1.21.0 and mcp>=1.28.

v2.1.0 — `mcp --expose` options; the account is the boundary

Choose a tag to compare

@zw008 zw008 released this 15 Oct 08:22

vmware-log-insight mcp accepts the family's new --expose / --allow-write options (vmware-policy 1.20.0). This server has
no write tools, so --expose read offers the same tools as the default; the options exist so every server in the
family can be started the same way. references/setup-guide.md now says why the service account must itself be
read-only: an agent with a shell can reach the platform without this skill. Requires vmware-policy>=1.20.0.

v2.0.0 — MCP tools renamed verb-first

Choose a tag to compare

@zw008 zw008 released this 14 Oct 09:45

Breaking for MCP clients: all 7 tool names changed. The family now uses one naming convention, verb
first (list_…, get_…, search_…), so an agent that learns one skill can guess the next. Where two skills
would otherwise ship the same name, a domain word is added: vmware-aria already has get_alert /
list_alerts, so this skill's alert tools are log_ alerts.

Old name (≤ 1.9.1) New name (2.0.0)
log_search search_logs
log_aggregate aggregate_logs
log_fields list_log_fields
log_version get_log_insight_version
alert_list list_log_alerts
alert_get get_log_alert
alert_history get_log_alert_history
  • Parameters, results and behaviour are unchanged (including the v1.9.1 query-constraint fix for issue #3).
    The audit log records the new names; CLI reads record their MCP twin's new name.
  • CLI commands are unchanged (vmware-log-insight search, aggregate, fields, alert list|get|history).
  • Deny rules in ~/.vmware/rules.yaml written with old names keep working with vmware-policy ≥ 1.18.0 (it
    matches both names); vmware-audit policy lists any rule that now matches more.

v1.9.1 — searches no longer fail with HTTP 400 (#3)

Choose a tag to compare

@zw008 zw008 released this 13 Oct 08:10

Every log_search / log_aggregate call (and vmware-log-insight search) was rejected by a real appliance with
HTTP 400, while doctor passed.
The query builder sent each constraint as three path segments —
timestamp/LAST/3600000, text/CONTAINS/error — but Log Insight reads a constraint as a field followed by ONE
segment holding the operator and value separated by a space: timestamp/LAST%203600000, text/CONTAINS%20error.
doctor never builds a query, which is why it stayed green. Reported in
#3; the reporter's hand-written curl had the right
form.

  • All constraints now use field/<OPERATOR value>: relative window, absolute >/< window, text CONTAINS, and
    every (field, operator, value) filter. EXISTS is sent as field/EXISTS (it previously got a trailing
    empty segment).
  • The operator+value segment is percent-encoded as a whole, so a value containing / or spaces still stays one
    segment.
  • New regression test_constraint_wire_grammar.py checks the path that actually leaves the HTTP client (not just
    the builder's string), including the exact request from the issue. Reverting the fix turns all three tests red.

Dependencies. uv.lock moves pyjwt 2.13.0 → 2.15.0 (supersedes Dependabot
#2; 2.15.0 carries an upstream fix for deeply nested
token payloads). pyjwt reaches this skill only transitively through mcp; the published wheel's requirements are
unchanged, so this only moves the locked dev/test environment.

v1.9.0 — MCP instructions name the configured targets

Choose a tag to compare

@zw008 zw008 released this 20 Sep 14:48

initialize hands the client this server's instructions, and for a skill whose every tool takes a target that
text is the only place the client learns which targets exist. Until now this one shipped a static description that never named them. The model then
called tools with no target, got whatever the default was, and answered confidently about the wrong system —
measured in vmware-monitor on 2026-09-15, where a standalone ESXi host was the default, so "how many VMs does the
vCenter have" was answered from that host.

The instructions now carry, built from the loaded config on every server start:

  • Configured targets: — each configured target with its host, and which one answers when none is named.
  • Choosing a target: — how to pick one from what the user asked, and to ask rather than guess when the
    request does not say and the targets would answer differently.

A config that cannot be read is said out loud, not dropped. On a machine that has not run init yet — every
new install — this server now reports Configured targets: could not be read (FileNotFoundError) — run vmware-log-insight doctor. instead of falling silent. A client shown no listing cannot
tell "this skill has no targets worth naming" from "this skill could not read them", and only the first reading
produces a confident answer about a system nobody chose. Only the error's type is included; its text quotes the
config path.

No tool, parameter or result shape changed. A new family gate (mcp_instructions_name_targets.py, in
family_smoke) probes every server under an empty HOME, so the check runs in the state a new user is in rather
than the one the developer happens to be in.

v1.8.17 — CLI reads are audited

Choose a tag to compare

@zw008 zw008 released this 15 Sep 06:00

No CLI read wrote ~/.vmware/audit.db — only MCP calls and CLI writes (@guarded) did. A live
vmware-aria resource list left the audit row count unchanged while the same read over MCP added a row.

Every CLI command that reaches Log Insight now passes the same guard() as its MCP twin and writes one
audit row under that tool's name (7 commands, @audited). Commands that reach nothing remote say so, with a reason (2, @cli_local).
A family gate now fails any CLI command that declares none of @guarded / @audited / @cli_local.

Behaviour change: a deny rule in ~/.vmware/rules.yaml whose operations name a read tool now stops
that CLI command too, as it already stopped the MCP call.

Requires vmware-policy>=1.15.0.

v1.8.16 — OpenClaw can load the skill

Choose a tag to compare

@zw008 zw008 released this 12 Sep 00:17

OpenClaw could not show this skill to the model. metadata.openclaw.requires listed
config file paths under requires.config, which OpenClaw reads as openclaw.json keys that
must be truthy — so the skill was "needs setup / not visible to the model" whatever was on disk
(verified on OpenClaw 2026.6.35). requires.env named an optional override and requires.bins
demanded a CLI that a plugin install (uvx) never has. requires is now anyBins: [<cli>, "uvx"];
the variables are still declared, under optional.env.

Install commands in the skill pin this release. ClawHub reviews SKILL.md and references/,
not the package they install, so an unpinned uv tool install vouched for code nobody reviewed.
Every install command for this package in the skill now names this version.

A config path written as ~/… now resolves. Every MCP example config and setup-guide snippet
sets VMWARE_LOG_INSIGHT_CONFIG to ~/.vmware-log-insight/config.yaml, but MCP clients pass env values verbatim and the
path was used unexpanded, so copying the snippet gave "Config file not found" for a file that was
there. ~ is now expanded in the variable and in --config.