Connect your Victron System to Claude/AI (hobby project)

Two MCP (Model Context Protocol) servers that let AI assistants (Claude Desktop, Claude Code, Cursor, Windsurf, or anything speaking MCP) read and — where safe — write to your Victron system.

  • victron-tcp — local LAN access over Modbus TCP + MQTT. Real-time, offline-capable, 900+ raw registers.
  • victron-vrm-mcp — remote access over the VRM cloud API. Self-hosted, MCP Connector compatible.

Both are MIT-licensed and published on npm. You can run them individually or together.


Contents

  1. Which server do I want?
  2. Server A — victron-tcp (local)
  3. Server B — victron-vrm-mcp (cloud)
  4. Using both together
  5. Example prompts
  6. Links

1. Which server do I want?

victron-tcp victron-vrm-mcp
Data source Modbus TCP + MQTT on your LAN VRM cloud API
Transport stdio (client spawns process) Streamable HTTP (you self-host)
Needs LAN access to the GX :white_check_mark: :cross_mark:
Works away from home :cross_mark: :white_check_mark:
Works when internet is down :white_check_mark: :cross_mark:
Latency ~50 ms (real-time) ~15 min (VRM sampling interval)
Raw register access :white_check_mark: 900+ registers :cross_mark:
Tools 32 52
Prompts / workflows 23
Writes Read-only today; MQTT writes on roadmap Alarms, tags, Dynamic ESS, access mgmt — confirm-gated
MCP Connector API compatible :cross_mark: (stdio) :white_check_mark: (HTTPS)
Auth None (trusts LAN) Per-request VRM personal access token

Rule of thumb: on your LAN → victron-tcp. Anywhere else, or building an API-backed app → victron-vrm-mcp. Both at once is fine and often useful.


2. Server A — victron-tcp (local)

2.1 Prerequisites

  • Victron GX device on your LAN — Cerbo GX, Cerbo GX MK2, Ekrano GX, Venus GX, CCGX, or a Raspberry Pi running Venus OS.
  • Node.js 18+ on the machine running your MCP client.
  • MQTT (enabled by default on Venus OS) or Modbus TCP enabled on the GX.

2.2 Enable data access on the GX

Option A — MQTT (recommended, richer data model, auto-discovery):
MQTT-on-LAN is enabled by default on modern Venus OS. To verify: Settings → Services → MQTT on LAN (SSL) or MQTT on LAN (Plain text).

Option B — Modbus TCP (needed for raw-register access):
Settings → Services → Modbus TCP → ON. Default port: 502, default unit ID for the GX: 100.

You can enable both; the server will use whichever transport you configure.

2.3 Install per client

Claude Desktop / Cursor / Windsurf (JSON config)

Add to claude_desktop_config.json (Claude Desktop), ~/.cursor/mcp.json (Cursor), or the equivalent Windsurf config:

{
  "mcpServers": {
    "victron-tcp": {
      "command": "npx",
      "args": ["-y", "victron-tcp"],
      "env": {
        "VICTRON_HOST": "192.168.1.50",
        "VICTRON_TRANSPORT": "mqtt",
        "VICTRON_PORTAL_ID": "your-portal-id"
      }
    }
  }
}

Restart the client after saving. You should see victron-tcp appear in the MCP servers list with 32 tools and 23 prompts.

Config file locations:

  • macOS (Claude Desktop): ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows (Claude Desktop): %APPDATA%\Claude\claude_desktop_config.json
  • Cursor: ~/.cursor/mcp.json
Claude Code (CLI)

Single-line install:

claude mcp add-json victron-tcp \
  '{"type":"stdio","command":"npx","args":["-y","victron-tcp"],
    "env":{"VICTRON_HOST":"192.168.1.50","VICTRON_TRANSPORT":"mqtt"}}'

Verify:

claude mcp list

Remove if needed:

claude mcp remove victron-tcp
Don't know your GX IP? Let the AI find it

Install with no environment variables, then prompt:

“Find my Victron GX device on the network and set it up.”

The victron_network_scan + victron_setup tools will probe the LAN, test transports, discover devices, and return a config block you can paste back.

2.4 Environment variables

All optional — set them to avoid passing arguments on every call.

Variable Default Description
VICTRON_HOST (none) GX IP or hostname
VICTRON_TRANSPORT modbus modbus or mqtt
VICTRON_PORTAL_ID (auto) VRM portal ID (MQTT only — shown on the GX under Settings → VRM online portal)
VICTRON_MODBUS_PORT 502 Modbus TCP port
VICTRON_MQTT_PORT 1883 MQTT broker port
VICTRON_UNIT_ID 100 Default Modbus unit ID (the GX itself)

2.5 First-run smoke test

In your MCP client, ask:

“Give me a system overview from victron-tcp.”

That calls victron_system_overview and should return battery SOC, PV power, grid power, AC consumption, and ESS status. If it works, you’re done.

2.6 Troubleshooting

Symptom Likely cause & fix
ECONNREFUSED Modbus TCP not enabled on the GX, or wrong port.
ETIMEDOUT Wrong VICTRON_HOST, firewall, or GX on a different VLAN.
No devices found via MQTT VICTRON_PORTAL_ID missing or wrong. Check Settings → VRM online portal → VRM Portal ID.
“Unknown unit ID” on Modbus Run victron_discover — some devices sit on non-default unit IDs.
Tool call hangs Check client logs (see below). Usually a transport mismatch.

Log locations (Claude Desktop):

  • macOS: ~/Library/Logs/Claude/mcp-server-victron-tcp.log
  • Windows: %APPDATA%\Claude\logs\mcp-server-victron-tcp.log

For deeper debugging, use the MCP Inspector:

npx -y @modelcontextprotocol/inspector npx -y victron-tcp

3. Server B — victron-vrm-mcp (cloud)

3.1 Prerequisites

  • Node.js 18+ on the host that will run the server.
  • A VRM personal access token (see below).
  • Public HTTPS if you want the Anthropic MCP Connector API to reach it. Not required for local testing.

3.2 Get a VRM personal access token

  1. Log in to https://vrm.victronenergy.com.
  2. Preferences → Integrations → Access tokens → Create access token.
  3. Copy it immediately — VRM will only show it once.

:warning: VRM Bearer tokens (from /auth/login) are deprecated on 2026-06-01 per the official VRM OpenAPI spec. Use personal access tokens for anything new. The server still supports the Bearer scheme via x-vrm-auth-scheme: Bearer for backwards compatibility, but logs a warning.

For a quick read-only smoke test without an account of your own, the demo tenant works:

curl https://vrmapi.victronenergy.com/v2/auth/loginAsDemo

Use the returned short-lived token with header x-vrm-auth-scheme: Bearer.

3.3 Run the server

Option A — npm (recommended)
# One-off, no install
npx victron-vrm-mcp

# Or install globally
npm install -g victron-vrm-mcp
victron-vrm-mcp

Listens on http://127.0.0.1:3000/mcp by default.

Option B — from source
git clone https://github.com/lubosstrejcek/victron-vrm-mcp.git
cd victron-vrm-mcp
npm install
npm run build
npm start
Option C — Docker (one-liner)
docker run --rm -it -p 3000:3000 \
  -e HOST=0.0.0.0 \
  -e ALLOWED_ORIGINS="https://claude.ai" \
  node:22-alpine \
  sh -c "npx -y victron-vrm-mcp"

A dedicated image is on the roadmap.

3.4 Expose over HTTPS (Cloudflare Tunnel)

The MCP Connector API requires a public HTTPS endpoint. Cloudflare Tunnel is the simplest path because it needs no open inbound ports.

# One-time
cloudflared tunnel login
cloudflared tunnel create vrm
cloudflared tunnel route dns vrm victron-vrm.example.com

# Run
cloudflared tunnel run --url http://127.0.0.1:3000 vrm

Your server is now reachable at https://victron-vrm.example.com/mcp with a valid cert. Alternatives: nginx/Caddy reverse proxy in front of Let’s Encrypt, Fly.io, or the upcoming Cloudflare Workers adapter (shipped in v0.3.0).

Set ALLOWED_ORIGINS to restrict which origins may call you:

ALLOWED_ORIGINS="https://claude.ai,https://api.anthropic.com" \
HOST=0.0.0.0 \
npx victron-vrm-mcp

3.5 Connect clients

Anthropic Messages API (MCP Connector)
{
  "model": "claude-opus-4-7",
  "messages": [{"role": "user", "content": "Summarize my sites."}],
  "mcp_servers": [{
    "type": "url",
    "url": "https://victron-vrm.example.com/mcp",
    "name": "victron-vrm",
    "authorization_token": ""
  }],
  "tools": [{"type": "mcp_toolset", "mcp_server_name": "victron-vrm"}]
}

The authorization_token is forwarded as Authorization: Bearer <token> on every request.

Claude Code
claude mcp add-json victron-vrm '{
  "type":"http",
  "url":"https://victron-vrm.example.com/mcp",
  "headers":{"Authorization":"Bearer YOUR_VRM_TOKEN"}
}'
Cursor / Windsurf (HTTP transport)
{
  "mcpServers": {
    "victron-vrm": {
      "type": "http",
      "url": "https://victron-vrm.example.com/mcp",
      "headers": {
        "Authorization": "Bearer YOUR_VRM_TOKEN"
      }
    }
  }
}
MCP Inspector (testing)
# Terminal 1 — start the server
npx victron-vrm-mcp

# Terminal 2 — launch the Inspector
npx -y @modelcontextprotocol/inspector

In the Inspector UI:

  • Transport: Streamable HTTP
  • URL: http://127.0.0.1:3000/mcp
  • Headers:
    • Authorization: Bearer <your-vrm-token>
    • x-vrm-auth-scheme: Token (or Bearer for /auth/loginAsDemo tokens)

3.6 Environment variables

Variable Default Description
PORT 3000 HTTP port
HOST 127.0.0.1 Bind address (use 0.0.0.0 behind a reverse proxy)
MCP_PATH /mcp Endpoint path
VRM_AUTH_SCHEME Token Default forwarding scheme. Bearer deprecated 2026-06-01
VRM_ALLOWED_SITES (unset) Comma-separated idSite allowlist. If unset, any site the token can access is allowed
ALLOWED_ORIGINS (unset) Comma-separated allowed Origin values. If unset, only same-origin + loopback accepted

3.7 Per-request headers

Header Purpose
Authorization: Bearer <vrm-token> Required. The VRM token to forward.
x-vrm-auth-scheme: Token|Bearer Overrides VRM_AUTH_SCHEME. Use Bearer for demo tokens.
x-vrm-skip-confirms: 1 Bypasses the confirm: true gate on destructive tools. Automation only — logged as a warning.
mcp-protocol-version Must be 2025-06-18 or 2025-03-26.

3.8 Destructive tools & confirm gate

Every tool that writes, deletes, or changes access is confirm-gated server-side. A first call without confirm: true in the arguments is refused with an explanation of what would happen. The client must resend with { "confirm": true } to actually execute.

Destructive tool categories:

  • Alarms (vrm_add_alarm, vrm_edit_alarm, vrm_delete_alarm, vrm_clear_alarm)
  • Tags (vrm_tags_add, vrm_tags_remove, vrm_set_favorite)
  • Forecasts (vrm_reset_forecasts)
  • Site settings (vrm_set_site_settings)
  • Dynamic ESS (vrm_set_dynamic_ess_settings — writes schedules, b2g, price schedule, battery kWh)
  • Access management (vrm_invite_user, vrm_unlink_user, vrm_set_user_rights, …)
  • Access tokens (vrm_create_access_token, vrm_delete_access_token — the latter can self-lockout with "*")
  • Custom widgets (create/patch/delete)

For scripted automation you can opt out system-wide by sending x-vrm-skip-confirms: 1. Do not do this in interactive sessions.

3.9 Security model at a glance

  • Origin header validation (DNS-rebinding defense)
  • Strict Accept + Content-Type on POST
  • Bearer token never stored, never logged (logger strips token/authorization keys)
  • Zod schema validation on every tool argument
  • Base-URL host pin — client refuses anything other than vrmapi.victronenergy.com over HTTPS
  • Optional VRM_ALLOWED_SITES allowlist
  • Error body redaction — VRM errors reduced to error_code: errors-text, truncated

Full details in SECURITY.md.

3.10 Troubleshooting

Symptom Likely cause & fix
401 Token missing, malformed, or expired. Check Authorization header.
403 Token valid but site not accessible (or blocked by VRM_ALLOWED_SITES).
400 Origin not allowed Add the client origin to ALLOWED_ORIGINS.
400 Unsupported protocol version Client sent an old mcp-protocol-version. Update the client.
Tool refused with “confirmation required” Expected behavior on destructive tools. Resend with { "confirm": true }.
429 with Retry-After VRM rate limit (200/window, 3 req/s). Back off.
Works locally but not via Cloudflare Tunnel Check that cloudflared points to 127.0.0.1:3000 and the public hostname resolves.

Server logs are one-line JSON to stderr.


4. Using both together

Running both in the same MCP client is the common case: victron-tcp for live state and raw registers, victron-vrm-mcp for history, alarms you can change, and remote sites. When you prompt, name the server or the AI will pick based on context:

“Using victron-tcp, show me current AC loads per phase.”
“Using victron-vrm, list all my sites and any active alarms.”


5. Example prompts

Daily operations (victron-tcp):

  • “Run the daily-report prompt.”
  • “What’s my SOC and PV power right now?”
  • “Is my Quattro in Passthru? If so, why?”
  • “Explain why today’s yield is lower than yesterday.”

Planning & optimization (victron-tcp):

  • “Run energy-optimizer with goal = cost savings.”
  • “Check storm-prep — forecast is bad tomorrow.”
  • “Based on current loads, will my battery make it through the night?”

Commissioning & diagnostics (victron-tcp):

  • “Run commissioning for a new install.”
  • “Scan for devices and map the system topology.”
  • “Read registers 840–855 and explain them.”

Remote & multi-site (victron-vrm-mcp):

  • “List all my VRM sites and show any active alarms.”
  • “Get battery stats for site 12345 over the last 7 days.”
  • “Review my Dynamic ESS schedule and compare it to OTE spot prices.”
  • “Add an alarm on site 12345 when battery SOC drops below 20%.”

6. Links

Questions, bug reports, and feature requests → GitHub issues on the respective repo. Replies in this thread welcome for setup help and example use cases.

Last thing I would ever do…

There’s no way I’m going to hand over oversight of something as critical as my local energy infrastructure to a third party. The only exception I’d consider is using AI to process a limited, well-defined batch of historical data — strictly for advisory purposes when fine-tuning future control settings — not for real-time control or decision-making.

Hello @Rene2322 and @MikeD ,

Thanks for the feedback. This MCP is useful for the initial setup of connected GX components and additional development work with Grafana, Flux, etc., followed by Vibecoding. It’s helpful for gathering data and setting up mapping for historical data analysis.

However, it’s not intended for recurring historical data collection—that’s better handled by scripts rather than an LLM. Also, if you’ve read the documentation, you’ll see it currently supports read-only access, not write operations.

I’m curious—are you actually using this MCP server in your setup? It would help to understand your specific use case or concerns based on hands-on experience rather than theoretical objections.

That’s great because it suggests that genuinely useful applications will emerge from this in the future. I’m thinking of instructions to Claude that lead to changes in the Victron system’s settings, without requiring any programming via Node-RED.

But I’m not someone who wants to talk to their devices or furniture. Just as I see little point in controlling the living room lights with voice commands to Alexa, I see little point in talking to my Victron system to query its current data. I can see that data with a single mouse click in the console.

@TomBerger — You’re absolutely right. Asking “what’s my SOC?” when you can glance at the console is a step backwards. That’s not where the value is.

I think the real use case is implementation and commissioning, not daily monitoring:

For installers and system integrators:

  • victron_network_scan auto-detects GX devices on the subnet without knowing any IP. victron_setup then tests both Modbus and MQTT, discovers every connected device (inverters, MPPTs, batteries, tank sensors, gensets…), maps all unit IDs, and generates the config — in one step. On a new install with 10+ devices, that replaces a lot of manual register hunting.

  • The commissioning prompt runs a full checklist — discovers all devices, verifies firmware versions, validates wiring and configuration, and produces a pass/fail report. That’s an hour of clicking through menus replaced by one conversation.

  • device-inventory produces a complete device table with unit IDs, service types, and firmware ready to paste into documentation.

  • Scale matters for a residential system with one Cerbo and a few MPPTs, you know your setup. But for commercial installs with 20+ devices across multiple GX units, automated discovery and asset mapping saves real time.

For non-Victron developers and integrators:

This might be the most underrated use case. If you’re a home automation developer, an HVAC integrator, or building an energy management system, and you need data from a Victron system you’d normally have to learn Modbus TCP register addressing, unit ID assignment, Venus OS MQTT topic structure, scale factors, enum mappings… The MCP server abstracts all of that.

You just ask “what’s the grid power on L1?” and get a clean answer. The 942-register catalog and all the protocol complexity is handled for you. You don’t need to become a Victron expert to integrate with one.

For Node-RED development:

The nodered-check prompt maps all available MQTT topics on the Venus OS broker, shows the exact topic structure (N/<portalId>/<service>/<instance>/<path>), explains the keepalive mechanism, and lists writable registers. If you’re building a Node-RED flow to control ESS mode based on tariff schedules, the AI can tell you exactly which topics to subscribe to and which to write — without digging through the CCGX register PDF. It doesn’t replace Node-RED, but it makes developing flows significantly faster.

ESS tuning on new installs:

The energy-optimizer reads your current ESS mode, grid setpoint, battery limits, and Dynamic ESS state, then recommends specific changes based on a goal you pick (self-consumption, cost-savings, battery-longevity, backup-ready). “Set grid setpoint to -30W to avoid export” or “switch to Optimized with BatteryLife” — actionable advice instead of guesswork.

You’re right that once an off-grid system is running and stable, there’s less need for this — you know your system, your Node-RED flows are built, your settings are dialed in. The value is front-loaded: getting there faster with fewer mistakes. And for anyone integrating Victron into a larger system without being a Victron specialist — it’s an always-available translator between your world and theirs.

Victron have already been implementing carefully curated AI features into the VRM stack. Every other attempt to date with AI has been underwhelming. It only needs to be a few percent off to have consequences.
I would never encourage handing off initial setup to an AI, we have enough users who lack experience attempting setups, empowering more is asking for trouble, and we’re already dealing with too many topics of failed efforts following poor AI advice.

I have used n8n and the api to extract data. The local device does not store trends and the real value is interpretation of longer term trends.
For critical infrastructure I will be keeping an llm as far away from it as possible.