Skip to main content
Glama
SinclairQuantumLab

Dispenser Conditioning MCP

Dispenser Conditioning MCP

This Python 3.13 MCP server exposes a bounded Streamable HTTP interface for:

  • one read-only Pfeiffer HiCube Neo G1 total-pressure observation; and

  • one operator-bound Siglent SPD3000 dispenser-power topology.

Pressure is total gauge pressure, not rubidium partial pressure. Neither a pressure trace nor a power-supply readback verifies dispenser activation. This server deliberately stops short of autonomous conditioning orchestration.

See the exact pressure contract, power-control contract, and transport/deployment contract, plus the verification report.

Quick start

One HTTP process serves either real instruments or an internal Python simulator. The operator selects backend = "hardware" (default) or "simulation" in the main TOML. There is no fallback between them and no model-facing backend switch.

This Python repository runs on any supported host with Git, uv, and Python 3.13. Real-hardware first commissioning is read-only. Keep its control_enabled = false, and never commit the populated gateway-authentication file.

git clone --recurse-submodules https://github.com/SinclairQuantumLab/dispenser-mcp-server.git
cd dispenser-mcp-server
uv sync

The recursive clone checks out the pinned py-siglent-spd3000 source, and uv sync uses .python-version, uv.lock, and the editable local dependency declared in pyproject.toml. If uv is missing, follow its official installation instructions.

For the hardware backend, first copy the tracked templates to local runtime files only when those files do not already exist, then edit the copies:

cp settings/mcp-settings.toml.template.hardware settings/mcp-settings.toml
cp settings/hicube-neo-client-settings.toml.template settings/hicube-neo-client-settings.toml
cp settings/py-siglent-spd3000/gateway-settings.toml.template settings/py-siglent-spd3000/gateway-settings.toml

settings/.gitignore excludes actual *.toml recursively; templates stay tracked. Runtime paths are unchanged. MCP-owned settings use the current field set without schema_version; remove that obsolete key from local settings:

settings/mcp-settings.toml
settings/hicube-neo-client-settings.toml
settings/py-siglent-spd3000/gateway-settings.toml

The following configuration and deployment check are for backend = "hardware". For a hardware-free host, use the simulation instructions below instead; no live settings or populated gateway-auth file is needed.

Copy settings/py-siglent-spd3000/gateway-auth.toml.template to settings/py-siglent-spd3000/gateway-auth.toml, restrict it to the operator or service identity, and set the token only if required by the gateway; otherwise leave the token line commented. The populated file is ignored by Git. Fill every placeholder in the three nonsecret TOMLs and leave control_enabled = false for the first start.

Validate and start with the same commands on every supported host:

uv run python -m dispenser_conditioning_mcp.deployment_check
uv run dispenser-conditioning-mcp

Normal hardware CLI startup reads G1 and PSU once, printing PASS with pressure or PSU identity/output/current, or FAIL followed by the ordinary chained exception traceback. The first failed read aborts startup; the HTTP listener does not start. No output/settings writes occur. Simulation startup and ordinary application construction do not run these checks. These startup diagnostics are not run records.

The offline check validates local settings and imports without a device connection. Its stage codes identify configuration, transport, imports, authentication-file access, and server assembly failures. --diagnostic includes the exception class. These are operator diagnostics, distinct from sanitized model-facing tool errors. Ordinary local troubleshooting may inspect nonsecret settings, paths, endpoints, and logs; never disclose token contents.

Streamable HTTP always listens at /mcp. The default allow_remote_access = false binds 127.0.0.1:8000. To connect directly from another computer, set allow_remote_access = true and connect to http://<Pi-IP>:8000/mcp (or its resolvable hostname). port is a top-level integer setting. SSH forwarding is optional. This supervised native-client pilot rejects browser Origin headers on /mcp and has no built-in client authentication. The same process serves the read-only dashboard at /dashboard.

During first commissioning, call only read_vacuum_pressure and read_dispenser_power_state. See the detailed Raspberry Pi research guide for the supervised commissioning sequence.

One-time update from tracked settings

Before pulling this settings-template migration, back up your existing settings/ directory outside the checkout, including any operator credentials, and keep the backup private. Git may remove previously tracked clean TOMLs during the pull or refuse the pull when they contain local edits. Preserve those edits; do not use reset/checkout to discard them. Restore the needed actual TOMLs from your backup after updating, or copy templates only for missing files. Future actual settings are ignored and will no longer be replaced by tracked defaults.

Related MCP server: otgate

Independent simulation host

After the same recursive clone and ordinary uv sync, replace only settings/mcp-settings.toml with a copy of settings/mcp-settings.toml.template.simulation (preserve any existing operator profile first). For a fresh simulation host:

cp settings/mcp-settings.toml.template.simulation settings/mcp-settings.toml

Set allow_remote_access = true if the decision agent is on another machine, then run the same command:

uv run dispenser-conditioning-mcp

The simulator runs inside this process, not at another externally exposed port. The clone contains its canonical runtime at src/dispenser_simulator/; the parent project is not needed. One RecordingAdapter creates one run under runs/, with the same eight public tools, session IDs, records, protected human dashboard and internal observer file. Seed/scenario stay operator-only and out of MCP results. The example is a disclosed connectivity fixture, not a hidden scientific test. Before a blind run, choose private operator configuration and keep source/files, loopback, authenticated dashboard and terminal inaccessible to the remote agent.

New HTTP simulation defaults are synthetic production_dispenser, control_enabled = true, compliance_voltage_v = 1.0 V. The voltage is a simulation-only test value, not approved for live equipment. Existing model limits remain 6.4 A device ceiling and 0.2 A upward steps. Simulation reads and prepare/enable/set accept optional elapsed_s (0..86400 seconds, default 0). Each physical interaction irreversibly advances by the greater of that request and actual monotonic wall time since the previous interaction. The first call ignores pre-client server idle. Controls evolve the old output state before applying the new action. Shutdown has no future-delay argument. Decisions and dashboard views do not advance/reset the clock; their wall time counts at the next physical interaction. Results include timing (requested, wall, actual and cumulative virtual seconds); domain errors after advancement carry _meta.simulation_timing. Invalid interval/context does not advance the model. No intermediate gauge samples are invented, and physics equations are unchanged. The dashboard formats elapsed axes as MM:SS below one hour or HH:MM for longer runs (hours do not wrap), adding seconds or milliseconds when zoomed closely. Hover retains precise elapsed seconds. CSV units stay unchanged. The old developer stdio command retains its original 10.0 V default and explicit environment overrides. HTTP simulation does not import hardware adapters or read their settings/authentication. Installed dependency code is not device access. The legacy deployment-check command is for the hardware backend, not required here.

Tool surface

Tool

Input

Purpose

read_vacuum_pressure

none

Read one total-pressure snapshot

read_dispenser_power_state

none

Read identity, topology, native setpoints/readbacks, output state, and fixed safety limits

prepare_dispenser_power

action_context

Destructively overwrite the bound state: output off, zero current, then fixed compliance voltage

enable_dispenser_output

action_context + one startup-context-specific confirmation

Enable only from the verified prepared zero-current state after the required fresh human physical confirmation

set_dispenser_current

action_context, target_current_a, expected_current_a

Compare-and-set an absolute commanded load-current limit while output is on

shutdown_dispenser_power

none

Perform an energy-reducing destructive overwrite: required outputs off first, then currents zero

The unreleased session-recording interface extension adds a seventh tool, record_conditioning_decision(action_context, completion?), for a declared hold or finish without changing power. Normal prepare/enable/set actions require brief agent context; shutdown still accepts {} and executes before ordinary logging. Read results provide the session and observation IDs to reference. See the exact context/recording contract.

Both entrypoints share the MCP checkout’s run directory; simulator defaults use the _simulation_ label. One process creates one run. The server records raw JSONL and CSVs under runs/<UTC-date-time>_hardware_<8hex>/. Open http://<server-IP>:8000/dashboard for observations, control attempts/results, and declared rationale. A prominent source-mode strip distinguishes simulation, live-hardware records, and unknown/fixture data. Short record numbers link chart points to readable requests, results, decisions and supporting observations. Simulated sessions may additionally show a human-only internal-state panel from an associated observer file; this never changes MCP tool results or decision inputs. The phrase has two random words and two digits, changes each HTTP process, and is reusable during that process. Five incorrect logins block further login attempts for up to 60 seconds across the process; cookies remain separate random secrets. The dashboard shows the current phrase near the top to logged-in local and already-authenticated remote viewers, never anonymous visitors. It is valid until server restart and is not saved in records or static assets. Ordinary dashboard pages, assets, run lists and observation/action/decision data are public without login. Internal simulation state and run-management writes still require the operator phrase at /dashboard/login. The locked internal section does not poll or interrupt ordinary plots; unlocking preserves the selected saved run. Each HTTP process generates a new code, shown only in its startup terminal, server-loopback /dashboard/operator page, or already-authorized dashboard. Actual loopback connections can retrieve the phrase on the operator page, but must log in for protected data and actions. The code is reusable until restart, not a single-use OTP; it is never an MCP argument or result. Keep it and the resulting browser cookie out of the remote decision agent’s context. This does not isolate same-host agents with local file, loopback, or terminal access. See the dashboard access boundary.

Use View run to switch between the current process and saved runs in runs/. Selection changes only your browser; acquisition and recording continue unchanged. Refresh run list discovers newly saved folders. Legacy folders without the supported metadata/events files are listed as unavailable, without conversion. The dashboard samples no devices; it shows observation age. Completion/normal-response declarations are judgments, distinct from actual returned output-OFF status. No caller-side recording wrapper is required.

All schemas are closed with additionalProperties: false. No tool accepts a host, port, path, resource, transport, channel, topology, identity, compliance voltage, ceiling, tracking mode, or raw SCPI command. target_current_a and expected_current_a accept JSON integer or floating-point numbers only; strings and booleans are rejected before the controller is called.

All four mutating tools are marked destructive because they overwrite device state. Prepare and shutdown remain idempotent; enable and live current-setting are non-idempotent because physical heating accumulates even when an absolute target is repeated. Current setting itself uses compare-and-set: expected_current_a must match the live commanded load-current limit. A retry whose target is already live returns without a write only when the requested expected-to-target transition is valid.

Deterministic power boundary

Startup accepts exactly one deployment profile: parallel_ch1 on CH1, with load-current factor 2, a 3.2 A native ceiling, a 6.4 A maximum configurable load-current ceiling, and 6.4 A hardware capability. Startup also binds one explicit acceptance context: production_dispenser or no_load_test. The active context and its required enable confirmation are returned in structured safety limits.

The server never changes tracking mode. It requires live parallel mode before prepare, enable, or current change. A requested load-current limit is divided by two before the native CH1 current setpoint is written. The returned commanded_load_current_limit_a is therefore a command interpretation, not a measured load current. CH1 and CH2 current/voltage are queried sequentially in one batch, not simultaneously. measured_parallel_load_current_a sums the two finite measured currents only when the queried mode is parallel; otherwise it is null. Voltages remain separate. Simulation uses explicitly labelled symmetric model channels. The CH1-only no-load current check is unchanged.

Every target is bounded by the operator cap, software maximum 6.4 A and the topology hardware ceiling. Under parallel_ch1, every positive increase must equal 0.2 A of commanded load current, which maps to a 0.1 A native CH1 step. Decreases are allowed. Live voltage must still match the fixed compliance voltage before and after a current write. Identity mismatch causes no write. Any uncertain post-write failure triggers one best-effort output-off then zero-current sequence, with no automatic retry. Under parallel_ch1, recovery commands and verifies both CH1 and CH2 in case the live topology drifted to independent.

shutdown_dispenser_power may proceed despite a topology mismatch after exact identity verification. For parallel_ch1, it commands and verifies both outputs off before commanding and verifying both current setpoints zero. The structured state remains the normal bound-CH1 view. Shutdown is software only, not a physical emergency stop, watchdog, output lease, or hardware interlock.

Immediately before enable_dispenser_output, the agent must obtain the physical confirmation selected at startup:

  • production_dispenser advertises only parallel_connection_confirmation="confirmed_parallel_ch1", after the human verifies the approved physical parallel CH1 dispenser wiring.

  • no_load_test advertises only no_load_test_connection_confirmation="confirmed_no_dispenser_or_unapproved_load_connected", after the human verifies that no dispenser or unapproved load is connected. Operator-approved metrology wiring, including a voltmeter or no wiring, is allowed by this acceptance context.

The wrong context's field or literal is rejected before a driver session opens. Instrument tracking mode cannot verify external wiring or no-load state. These literals are caller attestations, not cryptographic proof of human provenance; the MCP host must keep a real human approval in the loop for every enable action. Never use no_load_test for a connected dispenser.

No-load tests check fresh finite native current after each completed mutation against the inclusive ±0.001 A band. An outside-band or unavailable reading triggers best-effort verified two-channel output OFF, then zero current, and a process-local stop latch. Subsequent energizing is blocked in that process; explicit shutdown remains available with operator control authorization and matching instrument identity. An uncertain shutdown is reported, never assumed successful or automatically retried.

There is no durable safety file, pending guard, initializer, reset acknowledgement, or startup inspection gate. A new process starts unlatched. The human beside the instruments handles between-session inspection and state checks. Ordinary run records preserve observations and requests, not control authorization. No software check runs continuously or guarantees OFF after process death.

Development setup

From this directory:

git pull --ff-only
git submodule update --init --recursive
uv sync
uv run pytest tests/test_config.py tests/test_transport.py tests/test_protocol.py

The canonical Siglent driver is the Git submodule at dependencies/py-siglent-spd3000, pinned by this repository's gitlink. uv sync installs it as an editable local path dependency together with all of its declared dependencies. Runtime loads that fixed submodule src directory; no driver path setting, driver wheel, or separate install command is needed.

The canonical HiCube integration is the byte-for-byte vendored dependencies/hicube/hicube_neo_client.py. Its upstream commit and exact hash are recorded in dependencies/hicube/PROVENANCE.md; no separate HiCube checkout is required for this development workflow.

All automated tests use injected fakes. They do not contact hardware, resolve configured device hosts, scan a network, read credentials, or run the Siglent driver's hardware-marked acceptance tests.

Use focused tests for the changed behavior and Ruff on changed Python files; run Pyright when an interface change warrants it. Full suites, package builds, and installation audits are not routine pilot-development gates. Start the HTTP server with the quick-start command and register its URL in your MCP client.

Operator startup configuration

Package 0.6.1 uses the environment-variable-free operator interface introduced in 0.6.0, comprising three strict, closed TOML documents. Missing files, missing required values, placeholders, unknown keys, wrong TOML types, and invalid ranges deny startup before any device connection. The six hardware tools retain their structured observation/action results and hardware safety semantics. The unreleased session-recording extension changes normal control inputs and adds one declaration tool; it is not identical to the older v0.4.3 input schema.

File

Operator settings

settings/mcp-settings.toml

Explicit acceptance context, expected PSU serial, fixed compliance voltage, control flag, allow_remote_access (default false), port (default 8000),

settings/hicube-neo-client-settings.toml

HiCube host, port (default 4840), and timeout (default 5 s)

settings/py-siglent-spd3000/gateway-settings.toml

Gateway identifier, timeout (default 5 s), and minimum command interval (default 100 ms)

control_enabled and allow_remote_access default to false; port defaults to 8000. The acceptance context, expected serial, compliance voltage, HiCube host, and gateway identifier have no implicit deployment value and must be filled in.

The following deployment contract is fixed in code and cannot be weakened in a settings file: authenticated gateway connection, parallel_ch1, CH1, model SPD3303X, native ceiling 3.2 A, commanded-load ceiling 6.4 A, factor 2, and exact 0.2 A commanded-load upward step. The HiCube client, Siglent driver source, settings directory, and authentication path are derived from the source checkout. No MCP tool or normal operator setting accepts any of those paths.

Gateway token authentication is optional and enforced by the gateway. Copy settings/py-siglent-spd3000/gateway-auth.toml.template to settings/py-siglent-spd3000/gateway-auth.toml; the populated file is ignored. The server uses the driver's strict loader and passes the token only to the gateway client constructor. Do not put the token into MCP arguments, logs, committed files, or other settings. Its complete format is:

token = "<non-empty pre-shared token>"

No other root key is accepted. The MCP deliberately delegates parsing and validation to siglent_spd3000.load_gateway_auth(..., required=True) so its authentication contract cannot drift from the gateway implementation. The file must exist; missing/commented/blank tokens produce None, passed unchanged to the gateway client. Set a token only if the gateway requires it. Invalid TOML/types still fail; no token is fabricated. Direct socket, VXI-11, and VISA connections are denied by this deployment's startup policy. Hardware CLI startup validates configuration and reads both instruments, stopping at the first failed read. Tool calls open bounded sessions. Network exposure and hardware control are independent settings; enabling remote access does not enable control. See the transport contract.

When updating an existing checkout, preserve your edited settings before pulling: tracked TOML changes can conflict with upstream changes. Keep acceptance context, serial, compliance, control, instrument settings, and the untracked auth file. Remove transport and the entire [streamable_http] table; add allow_remote_access = false and port = 8000 at the top level. Set the boolean to true when remote clients should connect directly. Old transport keys are rejected rather than silently ignored.

Minimal no-load test acceptance sequence

For a supply with no dispenser or unapproved load connected, an operator may approve a low 1.0 V fixed compliance voltage for the first acceptance run. Operator-approved metrology wiring may be present. The immutable ceilings remain 3.2 A native and 6.4 A commanded load current; the agent must still execute only the reviewed first exact 0.2 A load-current step in this acceptance sequence.

  1. Keep outputs off and set parallel tracking mode through an operator-controlled out-of-band procedure. MCP intentionally exposes no tracking-mode command.

  2. Start with no_load_test, the exact bound identity, 1.0 V compliance, exact 0.2 A upward step, and control disabled. Read state and verify identity, output off, parallel mode, and an unlatched interlock.

  3. Restart with the same policy and control enabled. Call prepare_dispenser_power, then re-read state.

  4. Ask the human immediately before enable to verify that no dispenser or unapproved load is connected and that any present metrology wiring is operator-approved. Call enable_dispenser_output with a fresh action_context and no_load_test_connection_confirmation="confirmed_no_dispenser_or_unapproved_load_connected".

  5. Re-read state, set commanded load current from 0.0 A to 0.2 A with compare-and-set, and re-read state. Every completed mutation must produce a separate native current measurement inside the inclusive fixed [-0.001 A, +0.001 A] band or the process-local latch trips. No load-current draw or absence of a load should be inferred from the native measurement.

  6. Set commanded load current back to 0.0 A, call shutdown_dispenser_power, and perform a final read.

This sequence is a supervised interface acceptance test, not dispenser conditioning or activation evidence.

Integration and later safety layers

Register http://<server-IP>:8000/mcp as a Streamable HTTP endpoint in the MCP host. Keep the process running and inspect the eight-tool catalog before live reads. Use control_enabled = false during first catalog/read-only integration.

Before unattended autonomous conditioning, separate higher-level work must add a persistent safety supervisor/output lease, pressure freshness and trip logic, auditable run state, a physical hardware interlock/watchdog, and validated activation-decision policy. This MCP draft does not claim any of those layers.

operator-only startup policy
        |                         |
commissioned HiCube client   hardware-validated Siglent semantic driver
        |                         |
pressure normalization       deterministic topology/current controller
        |                         |
        +---------- strict MCP tools ----------+
                             |
              Streamable HTTP at /mcp

Dashboard time views and reported tokens

All pressure/power, internal-model and token panels share one wall/virtual clock and Fixed / Rolling / Full X range. Zoom or pan anywhere updates every chart. Fixed retains the range; Rolling follows new points with the current zoom width; Full fits all known plotted times. Zoom in Full switches to Fixed; zoom in Rolling changes its retained width. No new data means no rolling movement. Changing the clock/run selects Full. Full time range changes X only, never resets Y.

Each numerical panel has Auto-Y for finite points inside the visible X range; log pressure uses positive values only and hidden traces are excluded. Empty windows retain the previous Y range. Disable Auto-Y to preserve manual Y zoom. Inventory defaults to fixed 0–100%; request/result categories remain fixed. Token points use their existing record time, with usage ID and record number in hover details. Missing time coordinates are omitted, not fabricated. New model snapshots record actual UTC recorded_at separately from synthetic observed_at. Older rows without recorded_at are omitted in wall mode and remain available in virtual mode; no timestamp reconstruction or data rewrite occurs.

Callers may optionally include action_context.token_usage with a unique usage_id and nonnegative integer total_tokens. Optional input/output/cached counts and model identify provider-reported details; missing values are not zero. Input includes cached tokens and output includes reasoning when reported—do not add them again. Reuse the same ID when one inference supplies several MCP calls. The dashboard counts each ID once, keeps the first report on conflicts and warns. CSV preserves repeated submissions: deduplicate token_usage_id when analyzing usage offline. This is a reported subset, not measured app usage or a billing total.

Optional Codex caller usage checkpoints

The MCP server/Pi never reads Codex history. Pulling this repository alone does not collect caller metrics. The standalone tools/codex_token_usage.py helper runs only on the caller computer, against one explicitly selected rollout and one per-conditioning-run cursor. It does not discover threads or read other rollouts. Start a fresh baseline before a new run; prior development/thread usage is excluded. One caller owns the cursor.

Example in a caller script launched from this checkout (adapt the two explicit local paths; keep the cursor with that caller's local run notes):

from pathlib import Path
from tools.codex_token_usage import CodexUsageCheckpoint

usage = CodexUsageCheckpoint(Path("/explicit/caller/rollout.jsonl"),
                             Path("/explicit/caller/run/usage-cursor.json"))
usage.baseline()  # Once before the run, not before every action.

# For each already-chosen normal action/declaration with action_context:
try:
    supplied = usage.decorate(arguments)
except (OSError, ValueError, KeyError, TypeError) as error:
    print(f"Token accounting unavailable: {error}")  # Caller/operator diagnostic.
    supplied = arguments  # Optional metrics must not prevent an action.
result = await client.call_tool(tool_name, supplied)
meta = (result.meta or {}).get("dispenser_conditioning", {})
batch = supplied.get("action_context", {}).get("token_usage")
if batch and meta.get("recording_status") == "recorded" and meta.get("decision_id"):
    try:
        usage.acknowledge(batch["usage_id"])
    except (OSError, ValueError, KeyError, TypeError) as error:
        print(f"Token acknowledgement failed: {error}; preserve the action result, do not replay it.")

No acknowledgement means the same pending batch/ID is attached at the next checkpoint, without issuing or retrying any control automatically. A transport error or degraded recording must not trigger a hardware replay to repair usage. Call shutdown normally, without decoration. Keep the cursor if reporting fails.

Counts are actual newly reported cumulative-counter deltas since the acknowledged checkpoint, not lifetime totals or an estimate of this action's cost. Accounting may arrive after the inference that chose an action; a later action/declaration can carry that batch. Missing, incomplete or reset counters are unavailable, not fabricated zero. Cached tokens are already included in input; reasoning is already included in output. The helper does not infer a model name.

Request positions on simulated time charts

Real decision/receipt timestamps and virtual observation timestamps are different clocks. New simulator request/decision records retain the known virtual clock at receipt, before the call's elapsed-time advancement. For an older request without that clock, the viewer can place it at the same call's returned time, explicitly labelled as approximate placement rather than a request-time reading. Records are not rewritten; actual observations keep their own timestamps.

Dashboard history loading

The dashboard receives server-prepared display records, at most 200 per response, not full MCP response envelopes or duplicate CSV tables. It shows the first page immediately, then fetches history pages sequentially with a browser event-loop yield between pages. “Loading history” changes to “Caught up” when live polling takes over (one second between checks). Saved runs use the same paging.

Human-only model history is also paged at 200 snapshots, with fixed parameters once per response. The reader first confirms the selected single-run association in bounded scans. No model samples or instrument queries are generated by loading. Raw events.jsonl and CSV files remain unchanged on the server; the collapsed inspector shows dashboard record fields, not the original MCP envelope.

A dashboard deadline/network error keeps displayed data and retries. It does not mean that MCP controls, recording, or the equipment stopped. Paging bounds record count, not individual string bytes; the browser still retains all loaded points.

Operator current cap and explicit reload

Top-level max_load_current_A = 4.8 (capital A) sets the combined commanded load-current ceiling for hardware and HTTP simulation. Valid values are finite numbers greater than zero and no greater than 6.4 A; omission defaults to 4.8 at startup. It is not a measured parallel-current value. The software maximum 6.4 A / native 3.2 A / parallel 6.4 A device bounds are separate constraints; the exact 0.2 A upward step remains unchanged.

After the operator edits this key, the agent may call reload_dispenser_current_limit() with no arguments. The server reads only this field from its canonical settings/mcp-settings.toml. No value, path, decision context, device access, actuation or simulated-time advancement is required. Missing/invalid/unreadable values leave the old cap unchanged. No other settings (backend, credentials, control authorization, compliance) are reloaded.

The result gives previous/applied/effective caps, explicitly reports hardware unchanged, and recommends fresh state inspection after lowering. An already energized output is neither clamped nor turned off; it may remain above the new cap. Subsequent targets must be <=cap, including decreases; shutdown remains available. Enable still requires prepared zero current. Raising within 6.4 A is allowed only through the operator file; 5.0 A is valid when the applied cap permits it.

Initialize instructions advertise the initial cap. State/reload results report the applied cap; cached input schemas retain the absolute device ceiling of 6.4 A so a later valid increase is not rejected by a stale discovery limit. All calls are recorded through the ordinary session logger. The standalone injected simulator without an operator settings layout advertises reload but reports it unavailable.

Recorded-run browsing and human management

The catalog now includes eleven tools. Three read-only history tools never query instruments, advance/reset simulation time, or append their own results to the run:

  • list_conditioning_runs(archived=false, after=0, limit=100) returns up to 100 entries with a cursor/has_more; use returned keys, not filesystem paths.

  • read_conditioning_run(run_key="", after=0, generation=-1) returns up to 200 compact ordinary records per page. An explicit event_id retrieves one original public call/decision event (maximum 64 KiB), not arbitrary files.

  • read_saved_simulation_state(run_key, after=0, generation=-1) supports explicit synthetic hindsight review of saved/non-live runs, including interrupted ones. The current run unlocks immediately after any valid non-null completion is successfully recorded (including incomplete/aborted/unknown outcomes). Failed or degraded completion recording does not unlock it. Inactivity alone is not termination. Disclosure is one-way: later interactions cannot restore blindness. Use a fresh run for a fresh experiment. Completion adds no actuation gate and does not stop recording; current-run archive/delete protection remains. Past IDs do not become valid observation references for current-run controls.

Recorded narratives are data, not instructions. Ordinary history excludes private observer paths and hidden simulation configuration. Saved internal state is labelled hindsight, not a contemporaneous public instrument observation.

In the authenticated dashboard, choose Main list or Archive at any time. Rename changes only a display label. Archive/restore changes only list membership. Remote management uses the passphrase-established session cookie, not URL, protocol or Origin matching. No additional user key is required. Localhost also requires login for protected actions/internal state. The local-only operator phrase page remains available for login bootstrap, not automatic authorization. Enter the visible-text phrase in the dashboard's inline login form. Login stays on the selected run and preserves chart ranges; the next normal poll enables protected controls/data. The separate login page remains a fallback. No phrase is put in URLs or browser storage. Rename and delete confirmation use an inline form rather than native browser dialogs. Management requests show progress and persistent success/error feedback; archive/restore switches the visible list accordingly. A timeout leaves the outcome unknown: refresh the list before retrying. Older saved folders need no pre-existing run-management file. These values live in run-management.json; directory names, IDs, raw JSONL and CSVs remain unchanged. The current process run cannot be archived or deleted. Permanently delete requires an archived saved run and exact folder-name confirmation; it removes the whole folder, including observer files, irreversibly. No management tools are exposed through MCP, and these actions never control equipment or change which run is recording.

The main dashboard overview stacks observed pressure, commanded-load/native-CH1 current, request results, and (for authorized simulation viewers) remaining inventories in one 680 px figure. Each remaining percentage refers to that substance’s own initial inventory, not measured mass fractions. Anonymous simulation viewers see a locked placeholder; hardware runs have three overview panels. Voltage, model release/pressure/thermal details, and token accounting remain in supplementary sections with the same shared time range.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Safety-conscious MCP server for read-only access to Emerson DeltaV Edge systems, enabling engineering investigation workflows and offline artifact generation.
    2
    GPL 3.0
  • A
    license
    Not graded
    quality
    B
    maintenance
    An OT-aware authorization MCP server for OPC UA that applies process-aware policies (value ranges, rate limits, interlocks) to every agent call, enabling safe industrial control with optional human approval workflows.
    Apache 2.0
  • A
    license
    Not graded
    quality
    C
    maintenance
    MCP server for reading and controlling an OWON SPE6103 programmable DC power supply over USB serial, with safety checks and verified SCPI commands.
    MIT
  • A
    license
    A
    quality
    C
    maintenance
    Enables read-only PostgreSQL interaction through safe query execution, query planning, table and column inspection, and privilege checks, with multi-layer defenses against write operations and transaction-control exploits.
    5
    MIT