Skip to content

Expose Core measurement-quality reasons and energy provenance through MCP diagnostics #42

Closed
srcfl/ftw
#1746

Description

@hannesb90

Problem

FTW Cloud's MCP connector can read live values and historical series, but it does not expose the diagnostic reasons and underlying energy/measurement provenance needed to troubleshoot a house-load failure. This forced the operator to use SSH, Docker and a direct LAN API request despite having an authorized FTW1 MCP connection with ftw.diag.run scope.

Real-world case on Core v0.152.1-beta.1, with the new Docker 0.x deployment. Related Core issue: srcfl/ftw#1744.

What MCP exposed

  • status: fresh grid_w, battery_w, pv_w, ev_w and driver/source freshness, but no load_w field/value and no household-load failure reason.
  • health_get: meter live and 3 drivers OK / 1 offline, but no indication of which source invalidated the house balance.
  • history_query: load_w = null in every bucket checked, without the reason for the gap. This is aggregated history rather than Core's energy ledger with source, coverage and quality.
  • drivers_status and config_get are useful, but alone cannot explain the load_estimate failure.
  • diag_run and events_list are listed in internal/mcp/tools.go with descriptions explicitly stating they are not yet served by the box (currently E_UNKNOWN_OP). An authorized diagnostic scope therefore does not provide the promised checks.

What the local FTW Core API exposed

The same box answered the read-only GET /api/status over LAN:

grid_w: -109.96
bat_w: -3874
load_w: null
history_reason: missing:easee:ev
load_estimate:
  watts: null
  energy_wh: null
  method: reported_energy_balance_v3
  reason: missing:easee:ev

Further read-only configuration inspection showed:

drivers:
  - name: easee_cloud
    lua: drivers/easee_cloud.lua
loadpoints:
  - id: Laddbox
    driver_name: easee

This reveals a dangling charger binding (easee vs easee_cloud) rather than a site-meter issue. The operator had previously tested both Zap and Pixii as site meters without resolving it. The mismatch and runtime error are verified; relinking the loadpoint was suggested, but the fix outcome has not yet been verified.

Why this matters

The MCP response told us that house-load history was unavailable, not why. We could not distinguish missing:easee:ev from timing, staleness, skew or invalid-balance causes until the owner executed a terminal command. The phone app's instantaneous balance and the web UI's qualified interval estimate also differed, making this diagnostic metadata essential.

Requested change

  1. Add a read-only, scoped diagnostic view/tool of the current Core measurement quality, preferably reusing Core's existing /api/status semantics. Expose load_w, history_quality, history_reason and load_estimate metadata (watts, reason, method, from_ms, to_ms, end_age_ms, timing_basis, energy_basis, etc.), with explicit null/unknown states.
  2. Provide a source/flow-level reason and a safe driver↔loadpoint association where possible, so missing:<driver>:ev can be diagnosed without manual LAN access. Respect redaction for addresses, secrets, credentials, device serials, and personal identity.
  3. Expose or provide safe read-only equivalents for /api/energy/history (Wh, quality, provenance, sample counts) and /api/series / /api/series/catalog (raw observations and timestamps), so missing energy or bad time coverage can be traced rather than inferred from aggregated history_query.
  4. Implement and validate diag_run (and events_list when ready), or do not present unavailable operations as functional diagnostics; return a clear capability/unsupported response.
  5. Keep the connector least-privilege: authorized diagnostic scope, explicit allowlist and response sanitization, read-only only; do not offer arbitrary HTTP passthrough, configuration mutation, control or credentials.
  6. Add end-to-end tests for a missing/dangling EV flow and for interval-quality failures. Confirm that MCP exposes the same reason as local Core while not leaking restricted data.

Ownership / implementation pointers

  • Cloud/MCP: srcfl/ftw-cloud/internal/mcp/tools.go (the exposed MCP tool list and constrained live/history reads).
  • Core: srcfl/ftw/go/internal/api/api_history_quality.go computes history_reason and load_estimate, while go/internal/api/api_agent_catalog.go enumerates available read-only diagnostic routes, including status, energy history, and original series. Coordinate through the existing scoped agent protocol rather than bypassing it.

This is a tooling/observability request distinct from srcfl/ftw#1744, the underlying dangling-loadpoint configuration issue.

Activity

  1. frahlg commented on Oct 19, 2026

    @frahlg
    Member

    Partly addressed by #41 and srcfl/ftw#1743, both merged today.

    The full technical MCP profile already has api_catalog and api_read for Core's listed read-only routes, including /api/status, /api/energy/history and /api/series. #41 directs troubleshooting through that path, explains why redacted config_get cannot prove an exact charger binding, and marks HTTP failures from diagnostic reads as MCP errors while preserving the path, status and response. Core #1743 adds exact charger-binding evidence to its diagnostic catalogue. Tests cover preservation of the binding names and error handling for a refused read.

    I am keeping this issue open. #41 does not add a sanitized measurement-quality view to the public profile, implement diag_run / events_list, or add the requested end-to-end missing-flow and interval-quality tests. The public profile still excludes api_catalog / api_read; full technical diagnostics deliberately retain technical identifiers, so they are not the restricted view requested here.

    The actual client profile, grant, running versions and failed call still need checking before calling the reported access problem resolved. These merges are not evidence of a Cloud deployment, a Core release, or recovery on the affected box.

  2. frahlg commented on Oct 19, 2026

    @frahlg
    Member

    Completed in #41 and #43, both now merged, with srcfl/ftw#1746 as the paired Core change.

    The new measurement_diagnostics tool is available in both MCP profiles under the existing diagnostic grant. Its fixed read-only views expose measurement reasons and null states, safe charger associations, energy quality/provenance/sample counts, and stored series with their timestamps and resolution. Opaque selections replace names and hardware identifiers; private fields stay out. It accepts no arbitrary HTTP path, configuration write or control.

    Unavailable diag_run and events_list operations no longer appear in tool discovery. Cached calls return an explicit unsupported MCP error without contacting Core. HTTP failures and incomplete replies also return errors rather than diagnostic success.

    Full vet/race/dev-tag/import checks and CI passed. End-to-end tests exercise OAuth, TLS and Noise through real Core read handlers and SQLite: missing/disabled EV reasons match Core, explicit repair restores live household load, an incomplete interval remains unknown, and energy provenance plus stored series survive the MCP path. Tests also cover denied grants, unsafe arguments, private-field removal and unsupported/error responses.

    Closing the implementation request. No Cloud deployment, Core release or box update was performed. The reporter's actual client profile, grant and runtime access have not been verified by these tests; a remaining live access failure needs its exact call and running versions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions