mcp-venus-os
This server exposes MCP tools to monitor and control a Victron Venus OS system via MQTT, with safety-gated write operations.
Read battery state of charge (SoC, voltage, current, power, temperature) with staleness info.
Read PV/solar charger power data, including total power across devices.
Read grid/AC status (power, voltage, current, frequency).
Read inverter mode and state for VE.Bus units.
List all discovered Victron devices.
Set inverter mode (on, off, charger_only, inverter_only) — requires confirmation and passes hard limits.
Set maximum charge current limit in Amps — requires confirmation.
Set battery SoC limit percentage — requires confirmation.
Connect to and disconnect from the MQTT broker; subscribe is a stub that returns an error.
Writes are gated by confirmation, hard limits, mode enum mapping, hardware contracts, and read-back verification; no automatic rollback.
Provides real-time data streaming from Venus OS via MQTT, including tools to connect, disconnect, and subscribe to MQTT topics for device data.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@mcp-venus-oswhat's the current battery SoC and PV power?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
MCP Venus OS
Venus OS deployment notes
Prefer the MQTT backend on a NAS, server, or workstation. It keeps the MCP/HTTP
runtime off a constrained GX while using the existing Venus MQTT gateway.
The Cerbo audit on 2026-09-12 found no native mcp-venus-os service; the documented
Synology deployment is a separate host and must be checked there.
For an off-device HTTP deployment, configure an operator-owned HTTPS endpoint and bearer authentication. Start with device writes disabled and no Cerbo SSH credentials. Keep the deployment manifest, image pin, credentials, verification record and rollback plan with the operator's deployment configuration. The deployment matrix and HTTP authentication setup below describe the supported transports and client configuration.
SSH package refresh downloads into a temporary /data staging directory and
validates that setup exists before copying into the installed tree. It retains
files absent from the release, including virtualenvs and local configuration,
and calls setup install without interactive stdin. Package-owned uninstall
handles service removal; there is no recursive-delete fallback. A release can
still replace same-named tracked files, so keep local secrets in the package's
documented external configuration files and retain a backup before upgrades.
MCP (Model Context Protocol) server for Victron Venus OS management. Primary transport is the Venus OS MQTT gateway (N/<portalId>/… reads, W/<portalId>/… writes) so the server can run off-device; direct D-Bus remains available for on-device installs.
Related MCP server: Victron VRM MCP Server
Release process
See the release strategy for validation, nightly, beta, RC and stable promotion rules, and the operator runbook for local commands.
Features
MQTT read path: subscribes to discovery markers and the exact telemetry paths consumed by tools and configured hardware contracts, then serves a stale-guarded cache (
stale,age_secondsper reading)Write tools over
W/topics: inverter mode, charge-current limit, SoC limit — exact hardware contracts and fresh read-back are required; no automatic rollback is providedSafety constraints: confirmation gate + hard limits enforced before any publish
Two server transports: stdio (Claude Code launches the process) or streamable HTTP with optional bearer-token auth (Synology Docker / shared use)
Optional D-Bus backend: unchanged behavior for installs running directly on the Cerbo
Quick Start
Installation
Not yet on PyPI. Install from GitHub:
pip install git+https://github.com/4alvit/mcp-venus-osOr for development:
git clone https://github.com/4alvit/mcp-venus-os
cd mcp-venus-os
uv syncPrerequisites (Cerbo GX)
Settings → Services → MQTT Gateway, mode = Local network (listens on LAN :1883)
Note the portal ID shown on the MQTT Gateway page (also
com.victronenergy.system/Serial)Verify:
mosquitto_sub -h <cerbo-ip> -t 'N/<portalId>/system/#' -vreturns telemetry
Configuration
Create a .env file from .env.sample or set environment variables:
TRANSPORT_BACKEND=mqtt # mqtt (default) | dbus (on-device only)
SERVER_TRANSPORT=stdio # stdio (default) | http
# MQTT — Venus OS gateway on the Cerbo
MQTT_HOST=<cerbo-ip>
MQTT_PORT=1883
MQTT_PORTAL_ID=<venus-portal-id>
MQTT_STALE_AFTER_SECONDS=60
# Safety
SAFETY_REQUIRE_CONFIRMATION=true
SAFETY_MAX_CHARGE_CURRENT=100
SAFETY_MAX_DISCHARGE_CURRENT=100
SAFETY_MIN_SOC_LIMIT=10
SAFETY_MAX_SOC_LIMIT=100
SAFETY_ALLOWED_MODES=on,off,charger_only,inverter_only,eco
SAFETY_ENABLE_WRITES=false # MUST be true to enable any write/control tools
# HTTP mode extras
SERVER_HOST=127.0.0.1 # 0.0.0.0 inside containers
SERVER_PORT=8000
SERVER_AUTH_TOKEN= # optional bearer token for HTTP modeRunning the Server
uv run mcp-venus-os # stdio (Claude Code launches this)
uv run mcp-venus-os --transport http # or SERVER_TRANSPORT=httpDeployment Matrix
Target | Transport backend | Server transport | Notes |
MP Kubernetes (shared) |
| HTTPS |
|
Synology Docker (alternative) |
|
| saved deployment layout; verify host availability |
macOS (fallback) |
|
| local process via |
On-device (Cerbo) |
|
| legacy mode, no gateway needed |
Docker:
cp .env.sample .env # fill in cerbo IP + portal id (+ token if exposing beyond LAN)
docker compose up -d # healthcheck hits GET /mcp until the MCP endpoint answersHTTP Auth Token
HTTP mode is protected by a static bearer token (SERVER_AUTH_TOKEN). Without it the
server runs unauthenticated — only sensible on a trusted home LAN.
Generate and apply:
openssl rand -hex 24 # generate once
echo 'SERVER_AUTH_TOKEN=<hex>' >> .env # add to the deployment .env
docker compose up -d # restart so the container picks it upClients then send Authorization: Bearer <token> on every request. Unauthenticated or
wrong-token requests get 401. For Claude Code:
claude mcp add --scope user --transport http venus-os \
https://venus-os.k3s.2560801.xyz/mcp \
--header "Authorization: Bearer <token>"Or via the project-level .mcp.json, which reads the token from the
VENUS_MCP_TOKEN environment variable (export VENUS_MCP_TOKEN=<hex> before launching
Claude Code):
{
"mcpServers": {
"venus-os": {
"type": "http",
"url": "https://venus-os.k3s.2560801.xyz/mcp",
"headers": { "Authorization": "Bearer ${VENUS_MCP_TOKEN}" }
}
}
}Claude Code Registration
Primary (shared MP HTTPS endpoint — see above). Fallback: launch the server locally so it works even when the NAS is down:
claude mcp add --scope user venus-os \
-e TRANSPORT_BACKEND=mqtt -e MQTT_HOST=<cerbo-ip> -e MQTT_PORTAL_ID=<id> \
-- uv --directory /path/to/mcp-venus-os run mcp-venus-osDSM notes (deployed at /volume1/docker/mcp-venus-os/):
The 2026-09-12 audit found this directory still present, but no MCP container in the NAS Docker inventory, including stopped containers. Treat the instructions below as the saved deployment layout, not evidence of a currently running endpoint. Verify the existing configuration and host before enabling it again.
Plain
docker compose(full path/usr/local/bin/docker) works fine; Container Manager is not required.Host port 8000 is taken by Portainer on typical DSM installs — remap in the compose
ports:(e.g."8080:8000").SFTP/scp may be disabled; copy files via
ssh ... 'cat > file'.The
.env(portal id, token) lives only on the NAS, mode 600.
Container Images
The reviewed publication mapping is ghcr.io/4alvit/mcp-venus-os. Candidate builds produce an OCI archive; approved stable bytes are promoted separately to the registry without rebuilding. Follow the operator runbook for the versioned tag and optional latest update. The former main/tag-triggered GHCR and Docker Hub publishers are retired.
Available Tools
Read Tools
Tool | Description |
| Battery SoC, voltage, current, power, temperature (+ |
| PV/solar charger power, voltage, current, yields (power falls back to V×I) |
| Grid power, voltage, current, frequency from the |
| Inverter mode, state, AC/DC power, temperature |
| Devices discovered from received MQTT topics |
Write Tools (Requires Confirmation)
Tool | Writes to | Notes |
|
| mode name → enum code via per-device table; unknown combos rejected before publishing |
|
| Amps |
|
| % — confirm exact BMS path on target battery |
MQTT Tools
Tool | Description |
| Connect to the Cerbo gateway and prime the read cache |
| Disconnect; previously accepted control values are not automatically undone |
| Stub — reports "not yet implemented" rather than pretending success |
Conditional Tool Groups (context-friendly)
Tools are registered only when their service is present, so installations without them never pay tool-schema context:
Group | Detected via | Tools |
|
|
|
|
|
|
|
| Cerbo management toolkit (below) |
Multi-instance reads: instance=0 → {"readings": [...], "total_power": …} for
every device of the type; explicit instance=N → single dict.
Cerbo SSH Management
When SSH credentials are configured, these register alongside the broker-detected groups; 🔒 = confirmation-gated:
Tool | Purpose |
| reachability, firmware version, addresses |
| firmware dry run |
🔒 | download + apply firmware |
🔒 | set root password (stdin→chpasswd) |
| SetupHelper + installed packages |
🔒 | SetupHelper package lifecycle |
🔒 | arbitrary command, output capped |
# .env (local/stdio runs)
SSH_HOST= # defaults to MQTT_HOST
SSH_USER=root
SSH_KEY_PATH=~/.ssh/id_ed25519 # preferred…
# SSH_PASSWORD= # …or password
CERBO_ROOT_PASSWORD= # used by cerbo_enable_ssh when not passedDocker deployments mount the key instead of passing secrets through .env:
mkdir keys && cp ~/.ssh/<cerbo-key> keys/cerbo_rsa
chown 999:999 keys/cerbo_rsa # uid of the container's app user
chmod 600 keys/cerbo_rsa # compose already mounts ./keys:/app/keys:ro
# compose sets SSH_KEY_PATH=/app/keys/cerbo_rsa; remove those lines to use
# SSH_PASSWORD from .env instead
docker compose up -dTo bootstrap access on a fresh Cerbo: GUI → Settings → General → set the root
password once (cerbo_enable_ssh automates it from then on).
Clients can discover the live surface at runtime via the MCP resource
venus-os://capabilities (also summarized in server instructions); full
reference in docs/CAPABILITIES.md.
MQTT Topic Map
The server speaks the Venus OS MQTT-Gateway protocol:
N/<portalId>/<type>/<instance>/<Path> reads (published by Venus)
W/<portalId>/<type>/<instance>/<Path> writes (published by us)
R/<portalId>/<type>/<instance>/<Path> request one current value
R/<portalId>/keepalive maintain notification publication
inverter/state inverter-control aggregate
tank/<n>/Level dbus-pump tank levelReads: broker subscriptions include shallow service items and
Mgmtmetadata, small discovery markers for internal services, and all telemetry fallback paths consumed by tools. Configured hardware contract targets and identity paths, companion capability topics, and explicit caller subscriptions are preserved. Unused nested settings and history stay off the receive socket. Explicit broad caller subscriptions can opt back into that additional traffic.Freshness: cache entries use actual notification receipt times; tool output carries
stale+age_seconds(thresholdMQTT_STALE_AFTER_SECONDS, default 60). Each connection requests the initial tree once, then renews Venus publication every 30 seconds with{"keepalive-options":["suppress-republish"]}. The owned decoder worker also requests exact observed tool/contract values every 30 seconds, at most eight reads per 250 ms and 512 per cycle, rotating larger catalogs. Discovery-only metadata is not periodically republished. Missing replies remain stale; sending a read or keepalive never changes an item's age. No wildcard read requests or automatic control writes are used.FlashMQ Serial identity:
system/0/Serialis also a legacy keepalive alias. When a contract or explicit subscriber requires it, the exact read uses the same suppression payload, avoiding a full-tree republish. A retained Serial replay only establishes that the item exists; a live notification is required before it can provide fresh identity evidence. This follows the FlashMQ gateway protocol. The suppression behavior is for FlashMQ; compatibility with the retired Pythondbus-mqttgateway is not claimed.Reconnects: concurrent reads share one MQTT connection and its background recovery loop. A connection wait times out after five seconds without creating a competing client or refreshing cached timestamps. Shutdown waits are bounded; a worker still stopping prevents a replacement from using the same client ID. Paho owns the network thread and wake-up socket so publications from other threads are queued; only the network thread writes MQTT packets. This prevents maintenance requests from interleaving with a partially sent packet.
Disconnect diagnostics: each warning includes bounded
mqtt_diagnosticsJSON containing the connection epoch, callback ordinal, queue depth/drop count, and monotonic ages/counts for notification receipt, PINGREQ attempts and decoded PINGRESPs, socket generation and network-thread liveness. A socket generation advances on socket open, including connections that never receive CONNACK. A ring of at most 12 transport events stays in memory until a disconnect; repeated callbacks omit the ring unless a new event has arrived. Public socket callbacks capture metadata before closure, when the passed socket is still open even thoughclient.socket()is already empty. The public log callback observes only Paho's two fixed ping events. Other log strings, topics, payloads, addresses and credentials are never retained or forwarded by these diagnostics; debug logging is not enabled. On Linux, events include best-effortTCP_INFOcounters/timers and kernel receive and send queue byte counts. Missing measurements have a fixed status and are omitted, never reported as zero. The send queue includes unsent and unacknowledged bytes; TLS buffers are not included. These sequential measurements are not an atomic snapshot. No socket reads, peeks, option changes or packet captures occur. Sampling happens only at socket open/close and ping-related events, never per telemetry message; no background sampler or second socket writer is introduced.pingreq_attemptprecedes Paho enqueueing the packet. The guardedoutput_drained_after_pingreqevent means Paho's output queue subsequently drained on the same live socket; closing the socket cannot generate this event. Neither proves delivery to the broker.pingresp_decodedrecords parser progress, not wire arrival, and thread liveness is not a network-loop heartbeat. These observations help distinguish client/TCP backlogs from a missing response but cannot establish the cause of a timeout on their own. Paho 2.1 can invoke the disconnect callback twice for one keepalive failure;disconnect_callbackandduplicate_in_epochidentify repeated callbacks in one epoch, not necessarily the same outage. An epoch advances only after a successful CONNACK, so failed reconnect attempts can also share it. Timers, freshness limits, subscriptions and reconnect behavior are unchanged.Writes: a value is published as JSON only to its hardware-qualified
W/…path. There are no periodic writes to additional paths and no automatic rollback on disconnect/shutdown. Persistence is device-specific.Verification: after each write the matching
N/…topic is polled for up to 5s (WRITE_VERIFY_TIMEOUT_S); timeout → explicit error, never silent success. A timeout does not prove rejection or undo a command that reached the device. The gateway keep-alive controls notification publication, not the lifetime of arbitrary control values.
Safety Model
Defense runs in order, before any publish:
Confirmation gate (
SAFETY_REQUIRE_CONFIRMATION=true): first call withoutconfirmed=truereturns a confirmation prompt instead of writing.Hard limits: charge/discharge current ≤ configured maxima; SoC limits clamped to
[SAFETY_MIN_SOC_LIMIT, SAFETY_MAX_SOC_LIMIT]; inverter modes restricted toSAFETY_ALLOWED_MODES.Mode enum mapping: only modes with a known device-type enum code reach the wire; anything else is rejected pre-publish.
Reviewed hardware contract binds the exact path and allowed semantics to fresh firmware, target and BMS identities; missing contracts deny writes.
Read-back verification closes the loop — an unacknowledged write is reported as failed.
VE.Bus /Mode uses 1 = charger only, 2 = inverter only, 3 = on, 4 = off;
3 is not Eco. The separate inverter service uses 5 for Low Power/Eco, while
solarcharger uses 1 for on and 4 for off. These mappings follow
Victron's D-Bus specification.
Existing hardware contracts with conflicting codes fail closed and require
review; the server does not rewrite them automatically.
Known caveats: the exact SoC-limit path depends on the battery
BMS. Also note that acceptance ≠ persistence: when another service owns a
path (e.g. a BMS driver continuously asserting /Dc/0/MaxChargeCurrent), Venus
acknowledges and echoes the written value but re-applies its own within seconds —
verified live, where a 45 A write to a BMS-owned 52 A limit echoed successfully
and snapped back ~3 s later. The tool reports acceptance;
whether the value sticks depends on which service owns the item.
Configuration options:
SAFETY_REQUIRE_CONFIRMATION- Require confirmation for write operations (default: true)SAFETY_MAX_CHARGE_CURRENT- Maximum allowed charge current in Amps (default: 100)SAFETY_MAX_DISCHARGE_CURRENT- Maximum allowed discharge current in Amps (default: 100)SAFETY_MIN_SOC_LIMIT- Minimum allowed SoC limit % (default: 10)SAFETY_MAX_SOC_LIMIT- Maximum allowed SoC limit % (default: 100)SAFETY_ALLOWED_MODES- Comma-separated list of allowed inverter modes
Architecture
graph TD
subgraph "Venus OS Hardware"
VOS[Venus OS / Cerbo GX]
DBUS[(D-Bus System Bus)]
MQTT_BROKER[(MQTT Broker)]
end
subgraph "MCP Server (mcp-venus-os)"
MCP[FastMCP Server]
DBUS_CLIENT[D-Bus Client]
MQTT_CLIENT[MQTT Client]
SAFETY[Safety Validator]
TOOLS[MCP Tools]
end
subgraph "Clients"
CLAUDE[Claude Desktop]
OTHER[Other MCP Clients]
end
VOS --> DBUS
VOS --> MQTT_BROKER
DBUS --> DBUS_CLIENT
MQTT_BROKER --> MQTT_CLIENT
DBUS_CLIENT --> TOOLS
MQTT_CLIENT --> TOOLS
SAFETY --> TOOLS
TOOLS --> MCP
MCP -.->|stdio/JSON-RPC| CLAUDE
MCP -.->|stdio/JSON-RPC| OTHERDevelopment
# Install dev dependencies
uv sync --dev
# Run linter
uv run ruff check src/
# Run type checker
uv run mypy src/
# Run tests
uv run pytestLicense
MIT License - see LICENSE file for details.
Contributing and security
See CONTRIBUTING.md for development, bug reports and proposals, SECURITY.md for confidential vulnerability reports and deployment boundaries, and the OpenSSF evidence index for assessment scope and verification.
Verify the SSH host key before upgrading
SSH management now verifies the Cerbo host key. Without SSH_KNOWN_HOSTS,
the client reads the standard ~/.ssh/known_hosts trust file. You can set an
explicit verified file path; the Compose example mounts keys/known_hosts at
/app/keys/known_hosts. Compare the device's SSH host-key fingerprint through
an independently trusted console or administrator before accepting it. A key
observed by ssh-keyscan alone is not proof of identity.
Unknown or changed host keys now fail closed. After a genuine firmware reflash, verify the new key independently before replacing the trusted record. Never disable host-key verification to work around a mismatch. The MCP API does not provide an insecure bypass. SSH access still uses its configured credentials, and write operations still require the existing safety gates.
SSH negotiation requires SHA-2/Ed25519/ECDSA authentication and ephemeral key exchange. Use trusted Ed25519/ECDSA host keys or RSA keys of at least 2048 bits. Legacy servers limited to SHA-1 must be updated before connecting.
Both server host keys and the private key selected by SSH_KEY_PATH must use
RSA of at least 2048 bits, NIST P-256/P-384/P-521, Ed25519 or Ed448. Weak host keys
are removed from the trusted set without changing hostname, port, hashed-host,
wildcard or revocation matching. A trust file containing only weak keys therefore
refuses the connection, including a later key exchange on an existing connection.
The selected client key is checked before connecting; failure does not fall back
to a password. No private-key content is included in the error.
The supported authentication inputs are an ordinary private-key file at
SSH_KEY_PATH and/or SSH_PASSWORD. SSH agents, default identity files,
PKCS#11 tokens, host-based/GSS authentication and SSH/X.509 certificates are not
used. This makes the key policy independent of ambient credentials. If an
installation relied on one of those previously implicit AsyncSSH behaviors,
configure an explicit supported key before upgrading. For a custom host trust
file use SSH_KNOWN_HOSTS; UserKnownHostsFile in an ambient SSH config does not
replace it. The client never disables host verification for an empty trust file.
To keep SSH management disabled, leave both SSH_KEY_PATH and SSH_PASSWORD
unset and restart the MCP server. The SSH tools are not registered in this mode;
the MQTT telemetry tools remain available. This does not disable or weaken MQTT
TLS or its independent credentials.
MQTT certificate policy
When MQTT_TLS=true, the owned Paho connection verifies the broker's certificate
and hostname, then checks every certificate in the verified chain, including its
selected trust anchor, before sending MQTT CONNECT or credentials. RSA keys must
have an actual modulus of at least 2048 bits; EC keys require at least 224 bits,
DSA requires a 2048-bit group and 224-bit subgroup, and Ed25519/Ed448 are supported.
OpenSSL can impose stronger restrictions. TLS is at least 1.2; stricter defaults
and the existing cipher selection remain intact.
This closes a boundary where OpenSSL security level 2 alone accepts a 2047-bit RSA
key. Reissue a weak broker or CA certificate instead of disabling verification.
The client keeps the same system trust and SSL_CERT_FILE/SSL_CERT_DIR behavior
as Paho's default tls_set(). MQTT protocol 3.1.1, connection ownership, retries,
subscriptions and the plaintext mode are unchanged. This does not secure the
plain MQTT mode or certify an external broker's configuration.
The supported runtime is CPython 3.11 or later with the project's existing
cryptography dependency. The guard uses the public verified-chain API when
available, and CPython's internal SSL-object API on 3.11/3.12. A runtime that
cannot supply its verified chain fails closed. The configuration does not expose
MQTT client-certificate or proxy settings; this change adds neither feature.
No system-wide SSL defaults or CA stores are modified.
tests/test_mqtt_tls.py exercises the actual application/Paho path with disposable
local brokers: trusted RSA 1024/2047 leaf, intermediate and root rejection,
strong RSA/EC acceptance, invalid issuer/hostname controls and zero MQTT credential
bytes on rejection. Separate low-security fixture clients validate each test
chain with normal CA/hostname verification. No physical device is contacted.
The helper is adapted under MIT from the reviewed
inverter-dashboard TLS policy
and FastAPI MQTT policy.
Available Tools
11 toolsget_battery_socA
Get battery state of charge.
instance=0 returns every discovered battery as readings; instance=N
a single device dict.
| Name | Required | Description | Default |
|---|---|---|---|
| instance | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations present, the description carries the behavioral disclosure burden and does a good job by revealing the dual-mode output behavior for instance=0 versus instance=N. It does not mention error cases or units, but it makes the core conditional behavior visible beyond what the simple schema shows.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences with no filler: the purpose is front-loaded and the parameter behavior is stated compactly. Every word contributes to either identification or correct invocation.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter getter with an output schema, the description covers the key behavioral branch and parameter interpretation. It lacks only minor context such as source of the instance index or behavior when no devices are found, but these are not critical given the output schema and simple interface.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema provides only an integer parameter with a default and no description, so schema coverage is 0%. The description fully compensates by explaining that 0 aggregates all batteries under 'readings' and non-zero values select a single device dict, giving the parameter meaning beyond its type and default.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource, 'Get battery state of charge,' which uniquely identifies this read operation among getters like get_pv_power and get_grid_status. It also clarifies that instance=0 returns all discovered batteries while instance=N returns a single device, adding scope and removing ambiguity.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage context is implied by the resource name and first sentence: the agent should call this when it needs battery state-of-charge data. However, there is no explicit guidance about when to prefer this over list_devices or how to choose a valid instance value, and no exclusions or alternatives are named.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_grid_statusA
Get grid/AC status.
instance=0 returns every discovered grid meter as readings;
instance=N a single device dict.
| Name | Required | Description | Default |
|---|---|---|---|
| instance | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the behavioral disclosure burden. It explicitly reveals the return-shape distinction between instance=0 and instance=N, and the word 'Get' implies a read-only operation. It does not discuss failure modes or empty discovery, but for a simple status query this is adequate transparency.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact and front-loaded: the core purpose is stated first, followed by the essential instance-parameter behavior in two terse clauses. Every line earns its place with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter read-only status tool with an output schema, the description covers the key usage and return distinction. It does not mention error handling or how meters become 'discovered', but those are minor gaps given the output schema and simple nature of the tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema provides only a bare integer parameter with a default, and schema description coverage is 0%. The description fully compensates by explaining the semantic difference: instance=0 returns every discovered grid meter as 'readings', while instance=N returns a single device dict. This is exactly the meaning an agent needs.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('Get') and identifies the resource ('grid/AC status'). It further clarifies behavior by explaining that instance=0 aggregates all discovered grid meters while instance=N returns a single device dict. It does not explicitly compare itself to siblings, but the resource is distinct enough for an agent to distinguish it.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives concrete guidance on how to use the instance parameter (0 vs N), which is useful. However, it does not explicitly state when to prefer this tool over alternatives like get_battery_soc or get_pv_power. The use case is implied by the resource name rather than clearly framed.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_inverter_statusA
Get inverter mode and state.
instance=0 returns every discovered vebus unit as readings;
instance=N a single device dict.
| Name | Required | Description | Default |
|---|---|---|---|
| instance | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the burden, and it discloses the key behavioral nuance: instance=0 aggregates all discovered vebus units under 'readings', while instance=N returns a single device dict. The verb 'Get' also signals a read-only operation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences, with the purpose front-loaded and the only parameter explained immediately after. There is no filler, repetition, or unnecessary detail.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter, read-only getter with an output schema, the description is largely sufficient. It does not mention a possible dependency on the MQTT tools listed as siblings, but that remains an inference rather than a clear requirement.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema only states that instance is an integer defaulting to 0. The description adds the essential semantics: 0 is a sentinel for all units, and a non-zero value selects a single device, which is entirely absent from the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states the action and object directly ('Get inverter mode and state'), then clarifies the data scope with the instance rule. This makes it clearly distinct from write siblings like set_inverter_mode and from getters for other resources.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No explicit when-to-use guidance, exclusions, or alternatives are provided. The agent must infer from the tool name that it is the read counterpart to set_inverter_mode, and there is no mention of list_devices for enumeration or any MQTT prerequisites.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_pv_powerA
Get PV/solar charger power data.
instance=0 returns every discovered solarcharger/pvinverter as
readings plus total_power; instance=N a single device dict.
| Name | Required | Description | Default |
|---|---|---|---|
| instance | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden of behavioral disclosure. It clearly explains the two behaviors: instance=0 returns all discovered devices with readings plus total_power, while instance=N returns a single device dict. This goes beyond the schema and gives actionable behavioral context.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences with no redundant wording. The main purpose is front-loaded, and the parameter detail follows in a compact, readable format.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple single-parameter getter, the description covers the core behavior and output shape. An output schema exists, so detailed return structure can be obtained there. Minor gaps like units or error handling do not undermine usability.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema only defines instance as an integer with default 0 and no description. The tool description compensates by explaining the meaning of instance=0 and instance=N, fully covering the semantic range of the parameter.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb and resource ('Get PV/solar charger power data'), clearly identifying the tool's function. It is distinct from siblings like get_battery_soc, get_grid_status, and get_inverter_status, which target different data domains.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage context is implied by the resource name but not explicitly articulated. The description explains what instance values do but does not state when to prefer this tool over alternatives or mention any exclusions. Minimal but adequate.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_devicesA
List all Victron devices visible to the server.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are available, so the description carries the full disclosure burden. It only states the action without mentioning that the operation is read-only, how the returned list is structured, or whether it should be used to obtain device IDs for sibling get_* tools. This goes beyond what the schema covers but still leaves key behavioral traits undisclosed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single sentence that is front-loaded with the verb 'List' and contains no filler. Every word contributes to the meaning, making it appropriately concise and well-structured for such a simple tool.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given that the tool has zero parameters and an output schema exists separately, the description is nearly complete. It would benefit from a brief note on use with sibling tools or clarification of 'visible to the server,' but these are minor gaps for a straightforward list operation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema has zero parameters, so there is nothing to explain. The description correctly implies that no arguments are required. Baseline for 0 params is 4, and no additional parameter documentation is needed.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb ('List') and a clear resource ('all Victron devices visible to the server'). It distinguishes itself from sibling get_* tools, which retrieve specific metrics, and from set_* tools that modify state. No ambiguity or tautology exists.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description does not explicitly say when to use this tool vs alternatives, nor does it mention any exclusions. The use case is implied by the nature of listing all devices, and the sibling tools are clearly per-device queries, so an agent can infer it is for discovery/enumeration. However, no explicit routing guidance is provided.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
mqtt_connectB
Connect to MQTT broker for real-time data.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description must disclose behavioral traits, but it only says 'Connect to MQTT broker'. It does not clarify whether the connection is persistent, whether authentication is required, what side effects occur, or if there are any limitations. This is a significant gap for a connection-establishing operation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single concise sentence that effectively states the core action. It is front-loaded and avoids unnecessary detail, though it could provide more context without becoming verbose.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the simplicity of the tool (0 params) and the presence of an output schema, the description is adequate for basic understanding, but it fails to explain important context such as the relationship to mqtt_subscribe and mqtt_disconnect. The lack of usage guidance and behavioral transparency makes it incomplete for the agent to select and invoke correctly in a sequence of operations.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema has zero parameters, so there is nothing for the description to clarify. The schema coverage is 100% vacuously, and per the baseline for 0 params, the description does not need to add parameter semantics. It correctly remains silent on parameters.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the action ('Connect to MQTT broker') and purpose ('real-time data'), which distinguishes it from sibling tools like mqtt_disconnect and mqtt_subscribe. It is specific and unambiguous, though it does not elaborate on the scope beyond 'real-time data'.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No guidance is provided on when to use this tool. It does not mention any prerequisites, alternatives, or that it should be called before mqtt_subscribe or after mqtt_disconnect. The agent is left without context for when this is appropriate relative to siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
mqtt_disconnectA
Disconnect from MQTT broker.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden of behavioral disclosure. It only states the action, not what happens if already disconnected, whether subscriptions are cleaned up, or any side effects. This is a significant gap.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, focused sentence with no wasted words. It is appropriately sized for such a simple operation.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the zero-parameter simplicity, the description is adequate but lacks context about prerequisites (e.g., an active connection being required). Sibling tools imply the need to connect first, but the description itself is minimal.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, so the baseline is 4. The description does not need to explain parameter details, and the schema confirms no parameters exist.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the action: 'Disconnect from MQTT broker.' It uses a specific verb and resource, and is distinct from sibling tools like mqtt_connect and mqtt_subscribe.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage (when you want to end the MQTT connection) but provides no explicit when-to-use or alternatives. Sibling tools context helps, but the description itself offers no guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
mqtt_subscribeA
Subscribe to MQTT topic pattern.
Not yet implemented - returns an error.
| Name | Required | Description | Default |
|---|---|---|---|
| topic_pattern | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description explicitly discloses a critical behavioral trait: 'returns an error' because it is 'not yet implemented.' This goes far beyond what annotations (none provided) would convey. It honestly tells the agent that any invocation will fail, which is exactly the kind of behavior an agent needs to know. There is no ambiguity about the tool's current executability.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two short sentences, with the core action front-loaded and the critical caveat immediately following. Every word earns its place: the first sentence states the intended purpose, the second explicitly warns of non-implementation and the resulting error. There is no fluff, redundancy, or unnecessary detail, making it highly efficient for an agent to parse.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a stub tool with a single parameter and no annotations, the description is largely complete: it tells the agent the tool is not functional and will return an error, which is the most important fact. The output schema exists, so detailed return values are not the description's responsibility. The only gap is the absence of any guidance on what to do instead (e.g., no mention of an alternative subscription tool or a future implementation date), but this is a minor omission given the tool is clearly non-functional.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema contains one parameter, 'topic_pattern,' with no schema-level description (0% coverage). The tool description says 'Subscribe to MQTT topic pattern,' which essentially restates the parameter name without adding semantics. It does not explain MQTT wildcard syntax (e.g., '+', '#'), the expected format, or any constraints on the pattern. Given the lack of schema coverage, the description fails to compensate, providing minimal added meaning beyond the parameter name.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly identifies the intended operation: 'Subscribe to MQTT topic pattern.' This uses a specific verb ('subscribe') and resource ('MQTT topic pattern'), and distinguishes it from siblings like mqtt_connect and mqtt_disconnect by naming a different action. However, the immediate disclaimer 'Not yet implemented - returns an error' tempers the clarity; the agent must reconcile the stated purpose with the actual non-functional behavior. It is not a tautology, and enough detail exists to understand the tool's intent.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides an implicit usage guideline: since the tool is not yet implemented and returns an error, it should not be relied upon for actual MQTT subscriptions. However, it does not explicitly say 'do not use' or recommend any alternative tool or workflow. 'Not yet implemented' implies the agent should avoid calling it, but no when/when-not conditions or sibling alternatives are mentioned, leaving the agent to infer that this tool is currently a stub.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
set_charge_current_limitA
Set maximum charge current limit in Amps.
Requires confirmation for write operations.
| Name | Required | Description | Default |
|---|---|---|---|
| current | Yes | ||
| instance | No | ||
| confirmed | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden of disclosing behavior. It does state that the operation is a write that requires confirmation, which is important context. However, it does not explain what happens upon confirmation, whether the setting persists, any side effects, or potential errors. The behavioral disclosure is minimal beyond the confirmation note.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences with no filler. The purpose is front-loaded in the first sentence, and the second sentence adds crucial operational guidance. Every word earns its place, making it highly concise and well-structured.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool is relatively simple, and an output schema exists, so return values are covered. However, the description lacks context around the 'instance' parameter and does not elaborate on when or how the tool should be used in a broader workflow. It is adequate but leaves notable gaps, especially given the confirmation semantics that could be more deeply explained.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate. It explains that 'current' is the maximum charge current in Amps and indirectly explains 'confirmed' via the write-confirmation note. However, it completely omits the 'instance' parameter, leaving its meaning and role unclear. The description only partially clarifies the parameters and fails to cover all three.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's action ('Set maximum charge current limit') with a specific resource and unit ('in Amps'), which unambiguously distinguishes it from sibling tools like set_soc_limit and set_inverter_mode. The verb-resource pairing is precise and self-contained.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description mentions 'Requires confirmation for write operations,' which provides a prerequisite for using the tool. However, it does not explicitly state when to use this tool versus alternatives, nor does it provide scenarios or exclusions. The guidance is limited to the confirmation requirement, so it is only partially helpful.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
set_inverter_modeB
Set VE.Bus inverter mode (on, off, charger_only, inverter_only).
Requires confirmation for write operations.
| Name | Required | Description | Default |
|---|---|---|---|
| mode | Yes | ||
| instance | No | ||
| confirmed | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations are absent, so the description carries the full disclosure burden. It usefully states that this is a write operation requiring confirmation, but it omits consequences of mode changes, reversibility, permissions, and failure behavior when confirmation is absent.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tightly worded sentences, front-loaded with the action and resource. Every sentence contributes information without redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no annotations, 0% schema descriptions, and three parameters, the definition leaves key invocation details missing: the meaning of instance and the fact that the default confirmed=false may block the write. Although an output schema exists, the input-side gaps make this incomplete for reliable invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate. It enumerates the required mode values and implies the confirmed parameter's purpose, but it provides no meaning for the instance parameter and does not explain that confirmed defaults to false.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb ('Set') and resource ('VE.Bus inverter mode'), and enumerates the four allowed mode values. This clearly distinguishes it from read-oriented siblings like get_inverter_status and other set_* tools that target charge current or SOC.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No explicit when-to-use guidance, no alternatives named, and no when-not conditions. The confirmation note is a prerequisite for invocation rather than a usage discriminator; an agent can infer usage only from the tool name and purpose.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
set_soc_limitB
Set battery SoC limit percentage.
Requires confirmation for write operations.
| Name | Required | Description | Default |
|---|---|---|---|
| instance | No | ||
| confirmed | No | ||
| soc_limit | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description discloses that the tool 'Requires confirmation for write operations,' which adds a key behavioral trait beyond the raw schema. However, it does not clarify how confirmation is provided (e.g., via the confirmed parameter), what happens if not confirmed, or any side effects. With no annotations, the description carries a heavier burden, but this is only partially fulfilled.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is extremely concise: two sentences, front-loaded with the core purpose. Every sentence earns its place with no redundant or filler content.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
While an output schema exists (so return values are presumably covered), the tool has multiple parameters and a confirmation mechanism that is under-specified. The description lacks vital context about how to execute a write (setting confirmed=true?), value ranges for soc_limit, and differences from sibling set tools. This leaves the agent uncertain about safe and correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must explain the parameters. It implies that soc_limit is a percentage, but instance and confirmed are entirely undocumented. The confirmation requirement hints at the confirmed parameter's purpose, but the mechanism and constraints are not explained.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description 'Set battery SoC limit percentage' clearly identifies the action (set) and the resource (battery SoC limit), and it is distinct from sibling tools like get_battery_soc or set_charge_current_limit. The purpose is unambiguous and directly maps to the tool name.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides no guidance on when to use this tool versus alternatives, or any prerequisites or exclusions beyond a vague confirmation requirement. It does not mention that this is for adjusting battery state-of-charge limits in contrast to other charge-related settings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
11 tool updates
v0.1.0- First observed
get_battery_soc - First observed
get_grid_status - First observed
get_inverter_status - First observed
get_pv_power - First observed
list_devices - First observed
mqtt_connect - First observed
mqtt_disconnect - First observed
mqtt_subscribe - First observed
set_charge_current_limit - First observed
set_inverter_mode - First observed
set_soc_limit
TDQS
Scored across 11 tools
Each tool has a clearly distinct purpose: setting inverter mode, charge current, SoC limit, MQTT operations, and device-specific data retrieval. No overlapping functionality that could cause confusion.
Consistent verb_noun pattern: set_inverter_mode, list_devices, get_battery_soc, mqtt_connect, etc. All names follow snake_case with clear action prefixes.
11 tools for a Venus OS MQTT server is well-scoped, covering the key operations (device listing, data retrieval, setpoints, MQTT management) without bloat.
Core read/write functionality is covered, but mqtt_subscribe is marked as not yet implemented, and there is no explicit tool to read real-time data from the broker despite MQTT tools. Minor gap: no tool for general MQTT publish or unsubscribe.
Maintenance
Related MCP Connectors
MCP server wrapping the Tesla Fleet API and TeslaMate API
An MCP server giving access to Grafana dashboards, data and more.
MCP server with quote and live cryptocurrency price tools, local and cloud-deployed transports.
Related MCP Servers
- AlicenseAqualityAmaintenanceConnect AI assistants to Victron Energy systems to read real-time solar, battery, grid, and inverter data from your local network via Modbus TCP or MQTT.3295 npm4MIT
- AlicenseBqualityDmaintenanceRead-only MCP server integrating with the Victron VRM API to monitor solar systems, batteries, alarms, and more.4126 npm6MIT
- AlicenseNot gradedqualityDmaintenanceA powerful MCP server that enables AI assistants like Claude to access, analyze, and optimize solar energy data from FoxESS inverters.3MIT
- AlicenseNot gradedqualityCmaintenanceMCP server for Solplanet ASW5-T inverter, enabling natural language queries about solar energy system status and control.MIT