Skip to content

Releases: ZenixSolutions/lumics-mcp

v0.1.2

Choose a tag to compare

@cs3gallery cs3gallery released this 31 Jul 23:06
fcfe4a7

Install: npx -y @zenixsolutions/lumics-mcpon npm (published with provenance).

23.6% smaller. 92 files and 755.5 kB unpacked → 48 files and 577.2 kB. No behaviour changes; the tool surface is identical to 0.1.1.


Changed

  • Source maps are no longer published. dist/**/*.map is excluded from the tarball, cutting it
    from 92 files and 748.7 kB unpacked to 48 files and 573.9 kB — about 23% off every npx
    invocation and every install.

    They were inert. The 44 maps 0.1.0 and 0.1.1 shipped point at ../src/*.ts, carry no
    sourcesContent, and src is not in the package, so nothing existed at the targets on a
    consumer's disk. Every consumer paid 181 kB for debugging support that could not work.

    They are still emitted by npm run build and still work locally, where the sources are present.
    The exclusion is a negated pattern in package.json files, not a build change, so nothing about
    the local development experience changes. Shipping resolvable maps instead would have meant
    publishing src and growing the package to roughly 1.15 MB; that trade-off is recorded in
    #9.

Added

  • The release workflow now verifies the changelog section is finished, not merely present.
    scripts/check-changelog.mjs fails the release on a missing or undated heading, a heading still
    marked Unreleased, an empty section, a missing comparison link, or scaffolding wording left in
    the body. release.yml runs it before npm ci, so a tag that cannot produce a release fails in
    seconds rather than after a full install and test run. Available locally as
    npm run check:changelog -- X.Y.Z.

    The previous check only grepped for the heading, which a section full of scaffolding satisfies —
    and did: 0.1.0 published with "Nothing below has shipped yet; this section is the release note
    under construction and is finalised at tag time" still in it, and CHANGELOG.md ships inside the
    tarball, so the release announced on the registry that it had not happened
    (#10).

    Verified against that exact published text, which the gate rejects on four counts. Be candid
    about the limit: the structural checks are exact, but the scaffolding check is a phrase list and
    only catches wording someone thought to write down.

    Quoted text is excluded from the scaffolding scan — inline code, fenced blocks, blockquotes and
    double-quoted spans, including spans that wrap across lines. That was not foresight. The gate
    failed this very release on its first run, because the entry you are reading quotes the wording
    the gate bans. A changelog documenting a scaffolding phrase is not scaffolding, and a gate that
    cannot tell the difference would push people to reword accurate notes to appease it.

  • tests/installation/package-contents.test.ts asks npm pack what it would publish and asserts
    the answer. It covers both directions in which files fails silently: too broad, which is how the
    maps shipped, and too narrow, which would publish a package that installs and cannot start. It
    also asserts no .env, key or .npmrc is packed, and that nothing outside dist/ and the four
    named documents appears at all. Verified it fails when the map exclusion is removed.

v0.1.1

Choose a tag to compare

@cs3gallery cs3gallery released this 31 Jul 15:45
339be54

Install: npx -y @zenixsolutions/lumics-mcpon npm (published with provenance).

If you are on 0.1.0, upgrade. lumics_create_ipaddress, lumics_update_ipaddress and lumics_delete_ipaddress addressed a route the Lumics API does not serve and could never have succeeded. The two read tools were unaffected.


Fixes three tools that could never have worked in 0.1.0.

Fixed

  • lumics_create_ipaddress, lumics_update_ipaddress and lumics_delete_ipaddress addressed a
    route that does not exist.
    They sent the PLURAL /ipsubnets/:id/ipaddresses segment, which the
    Lumics API does not route for any verb. All three now send the SINGULAR /ipsubnet/, which is
    what every IP address route uses. Verified against a live tenant on 2026-07-31, including a real
    create. The two read tools were unaffected and always worked.

    The captured contract was the source of the error, not a slip in the code. docs/reference/lumics-api-v1.md
    §13 Q1 documented a per-verb split — singular reads, plural writes — asserted it was "confirmed
    present in the vendor's own route definitions", and instructed readers not to "fix" it. Measured
    against the live API, there is no such split. §13 Q1 is corrected in place with the vendor's
    original wording retained alongside, and the measurements are recorded in §0.5 (M13–M16), §14
    defects 26–28, and docs/contract-runs/2026-07-31-run-04.md.

    Surfaced by a user bug report of a hung lumics_create_ipaddress call. The hang came from the
    prototype this server replaced; on 0.1.0 the same call fails in about 150ms with a clean 404.

Added

  • tests/contract/live-write-routes.test.ts — live routing coverage for every write path, not
    just IPAM. It mutates nothing: probes address ids no record holds and send empty bodies, so a
    routed path can answer without anything being created, changed or deleted.

    This closes the gap that let the defect ship. The contract gate was read-only by design (D-0006),
    so it had never issued a single write request, and 0.1.0 passed it with three broken tools. The
    four top-level POST creates remain deliberately UNVERIFIED rather than probed, because a
    top-level create has no parent id to falsify — recorded as such rather than asserted weakly.

Changed

  • Route probing must not use this project's own HTTP client. LumicsClient sends
    Accept: application/json, and the API content-negotiates its router 404 into JSON — which makes
    a dead route indistinguishable from a missing record. The first live run of the new suite passed
    its positive assertions while establishing nothing for exactly this reason. The probes now issue
    raw requests with Accept: */*, where an unrouted path answers an HTML error page, and the
    premise is stated in the classifier's own documentation.
  • README.md, CLAUDE.md, docs/TOOLS.md and docs/RELEASE.md no longer state the withdrawn
    per-verb rule. CLAUDE.md's "do not fix the API in code" guidance stands; only its example
    changed, since the old one would now lead an agent to reintroduce the defect.

v0.1.0

Choose a tag to compare

@cs3gallery cs3gallery released this 30 Jul 21:47
f6a59af

Install: npx -y @zenixsolutions/lumics-mcpon npm (published with provenance).

See README.md for client setup and the full configuration table.


First release.

Added

  • 39 tools, one for each of the 41 documented Lumics REST API v1.0 endpoints except the two token
    endpoints withheld on security grounds: collectors (5, spec §5), components and component types
    (5, §6), devices (7, §7), IPAM addresses (5, §8), IPAM groups (5, §9), IPAM subnets (5, §10),
    identity (2 of the 4 endpoints in §11), and metrics (5, §12). 37 are registered in a default
    deployment
    ; 20 under LUMICS_READ_ONLY=1.
  • stdio transport, distributed as the npm package @zenixsolutions/lumics-mcp and runnable with
    npx. LUMICS_TRANSPORT=http is refused at startup in this release: ADR-001 decision 3 makes
    v0.1 stdio-only and states that it opens no network listener at all, so the configuration path to
    the listener is closed rather than left reachable while three documents say it does not exist.
    src/transport/http.ts stays in the tree so v0.2 is additive, and the five LUMICS_HTTP_*
    variables are documented for forward reference only. Streamable HTTP is ADR-001 decision 4,
    scheduled for v0.2.
  • LUMICS_COMPANY_ID is optional. Without it the server starts, registers only the two tools that
    need no company (lumics_get_me and lumics_get_device_definition_components; three with
    LUMICS_ENABLE_TOKEN_REVOCATION on) and logs a warning. This is what makes the documented first-run
    flow possible: the way to discover a company id is lumics_get_me, and a server that refused to
    start without the id could not run the tool that finds it. Call lumics_get_me, set the variable,
    restart. A value that is supplied is still format-checked at startup.
  • Operation classification on every tool — Read, Create, Update, Admin, or Destructive — with the MCP
    annotations (readOnlyHint, destructiveHint, idempotentHint) derived from the classification
    rather than written by hand, so an annotation cannot contradict it. openWorldHint is true
    everywhere.
  • Per-tool reference documentation at docs/TOOLS.md: every tool's arguments,
    types, defaults, constraints, return shape, underlying endpoint, and gating.
  • LUMICS_READ_ONLY=1 safety switch, which registers read tools only.
  • Opt-in gates for the two highest-impact operations: LUMICS_ENABLE_BATCH_UPDATE for bulk device
    update and LUMICS_ENABLE_TOKEN_REVOCATION for token revocation. Both are registration-time
    controls: without the flag the tool is absent from tools/list entirely.
  • Human-friendly time windows on metric tools: a relative lookback such as 15m, 6h or 7d, or
    ISO-8601 from/to, converted internally to the API's epoch-millisecond fromMs/toMs. The
    window defaults to the last hour. Nobody has to compute epoch milliseconds. Reversed windows,
    epoch-seconds mistakes, windows wider than 366 days, a to in the future, and from combined
    with lookback are all rejected locally with an explanation.
  • Timestamp arguments require an explicit timezone. from/to on every metric tool and date
    on lumics_update_device_last_discovery accept a bare YYYY-MM-DD (meaning UTC midnight), an
    ISO-8601 timestamp carrying Z or a numeric offset, or epoch milliseconds. A timestamp with a
    time component and no zone — 2026-07-29T14:00:00 — is rejected, with a message naming the
    fix. Date.parse reads that form in the server's local timezone while reading a bare date as UTC,
    which shifted a window by up to fourteen hours while the response notes reported the shifted
    window: a wrong answer that looked internally consistent. On
    lumics_update_device_last_discovery the same input would have persisted a shifted discovery time
    to Lumics.
  • A default fields projection on lumics_list_devicesid, name, ipAddress, deviceType,
    collector, enabled, maintenanceMode — because a full device record is around 1.9 kB and the
    default limit of 100 could not fit the 25,000-character output budget: a default call returned
    thirteen of the hundred devices it asked for, with two disclosure notes giving opposite advice.
    The projection is disclosed in every response, an explicit fields argument replaces it, and
    fields: [] asks for whole records. No other list tool projects by default.
  • LUMICS_ALLOW_CROSS_COMPANY, off by default. Every tool is covered by the company pin: most take an
    optional companyId and, with the flag unset, a value differing from LUMICS_COMPANY_ID is refused
    with not_permitted. See Security below.
  • LUMICS_LOG_LEVEL, one of debug, info (default), warn, error or silent. Diagnostics have
    always gone to stderr — stdout is the MCP protocol channel — but there was no way to turn the
    verbosity up or off. debug adds a record per tool call with its duration, output size, whether the
    limit was reached and how many items the output budget dropped, which is what Troubleshooting needs
    when a tool returns less than expected. silent quiets stderr entirely, for a supervisor that treats
    any stderr output as a fault. The level is parsed in src/config.ts and applied by src/index.ts,
    so importing this package cannot change a host application's logging.
  • A default resolution of 60 dataPoints on metric calls, since the Lumics API requires dataPoints
    or width on every metric-data endpoint and rejects a call with neither. The effective value, and
    whether it was defaulted, is disclosed in the output.
  • Client-side ranking (topN, sortBy, sortDirection) for metrics/summaries, which accepts no
    limit, top-N or sort parameter of any kind. The output states that the ranking was applied by
    this server after fetching the full set, and reports how many items had no value at the sort path.
    Lumics keys its results by item class, and the trim is applied per class: with topN: 2 over two
    classes you can get four rows, and no ranking crosses a class boundary. The response says so whenever
    more than one class is present, rather than only when the output budget happened to drop something.
  • Local input validation ahead of the API: identifiers must be 24-character hex ObjectIds, IP
    addresses must parse as addresses, netmasks as dotted quads, MAC addresses as MAC addresses, and a
    PATCH with no changed fields is refused rather than reported as a successful no-op.
  • Output shaping with an optional fields projection and a LUMICS_MAX_OUTPUT_CHARS budget
    (default 25,000). The budget caps the entire text a tool returns, disclosure notes and JSON
    payload together: notes are reserved first and the payload is fitted to what remains. The one
    exception is disclosures that exceed the budget by themselves — they are emitted in full and the
    payload is reduced to nothing, because a disclosure is never dropped or shortened to save space.
    Arrays shed whole items from the end so what remains still parses and the loss is positional;
    every drop is disclosed with a count. The completeness note and the truncation note are generated
    together, so a response cut by both no longer tells you to raise the limit and to lower it in the
    same breath.
  • No limit is sent to a metric endpoint unless the caller supplies one — deliberately unlike the
    list tools, which default to 100. limit is optional upstream, and injecting a default silently
    truncated a multi-thousand-row time series in an order Lumics does not document, cutting across
    time as well as across components. An incomplete inventory looks incomplete; a series with holes
    looks like data. The output budget sheds from the end instead, and the row-count note on every
    metric response states which of the two happened and what it means for reading the series.
  • The captured Lumics API contract as a committed artifact at docs/reference/lumics-api-v1.md, so
    the contract the code targets is auditable and upstream drift is visible.
  • Governance and community documentation: README, CONTRIBUTING, SECURITY, CODE_OF_CONDUCT,
    CLAUDE.md, dependency policy, release policy, issue and pull request templates.
  • CI on every push to main and every pull request: typecheck, lint, format check, tests, build,
    secret scan, and a stdio startup smoke test on Node 20 and 22.

Changed

Everything in this section comes from the first contract run against a live Lumics tenant, on
2026-07-30, which contradicted the vendor documentation in the metric layer. The measurements are
recorded in docs/reference/lumics-api-v1.md §0, §12.5 and §14
defects 17–23; the decisions are
ADR-003.

  • BREAKING (tool surface): properties is now a required argument on
    lumics_get_company_metrics, lumics_summarize_company_metrics, lumics_get_device_metrics and
    lumics_get_device_item_metrics. Spec §12.0 marks it optional; the live API answers
    400 {"error":"Must supply required component metrics as properties parameter"} without it, so
    those four tools could not make a single successful call at all before this change. The break
    is therefore real in form and removes a call shape that never worked. It is required rather than
    defaulted because no metric name is correct for every module, and a default would turn every
    unqualified request into a confident answer to a question nobody asked. The syntax is
    <TypeGroup>.<metric>, comma-separated — Calculated.cpu. It stays optional on
    lumics_get_metric_summary (spec §12.4), where it is genuinely optional upstream and acts as a
    filter rather than a projection: supplying it returned count: 0 on a live tenant, dropping
    items rather than narrowing them.
  • **L...
Read more