Security
octopus-mcp gives an AI assistant access to your Octopus Energy account. This page explains what that means and how to set it up safely. To report a vulnerability, see the security policy.
Threat model
Section titled “Threat model”Four things need protecting:
- The MCP endpoint. Anyone who can send requests to
/mcpcan use every registered tool with your API key. That includes reading your address, meter details, half-hourly usage (which shows when you’re home or away), balance and bills, and, if you’ve allowed it, changing your EV charging. - The API key. An Octopus API key isn’t scoped: it can read everything on your Octopus login, across all its accounts, and make the same changes through GraphQL that octopus-mcp can, and some it can’t. It doesn’t expire until you regenerate it.
- The assistant’s judgement. A model can misunderstand a request, or be steered by malicious text it reads (prompt injection), for example from a web page or document pasted into the same conversation. octopus-mcp’s data mostly comes from Octopus, but tariff descriptions, device names and similar text are still passed to the model.
- Your data, on its way to the model. Whatever the tools return, such as your address, usage patterns and bills, is sent to your AI provider as part of the conversation. Check that you’re comfortable with your provider’s data handling.
The best defence is to limit what’s possible, not to rely on the model behaving.
Layers of protection
Section titled “Layers of protection”| Layer | Setting | What it does |
|---|---|---|
| Write switch | OCTOPUS_ALLOW_WRITES (off by default) |
When off, no tools that change anything are registered, and the raw GraphQL tool refuses mutations. |
| Toolsets | OCTOPUS_TOOLSETS |
Tools outside the listed toolsets don’t exist. The model can’t see or call them. |
| Secret-handling mutations | Built in | The raw GraphQL tool always refuses obtainKrakenToken and any mutation that issues or changes tokens, API keys or passwords, even with writes on. |
| Tool annotations | Built in | Each tool is marked read-only or not. Bump charges and suspending smart charging are marked open-world because they affect a real car, so MCP clients can ask for your confirmation. |
| Server instructions | Built in | With writes on, the model is told to confirm EV changes and joining Saving Sessions with you first. This helps, but it isn’t a security boundary. |
| No secret output | Built in | No tool returns the API key or a Kraken token. Error messages are scrubbed of both. Public tariff requests don’t send the key at all. |
| Redirect guard | Built in | Requests carrying the API key or token never follow a redirect to another host, and paged results are always fetched from the configured host. |
| Endpoint auth | MCP_AUTH_TOKEN |
Bearer token required on every request, checked in constant time. The http transport refuses to start without one. |
| Host allow-list | MCP_ALLOWED_HOSTS |
Rejects requests with an unexpected Host header. This blocks DNS-rebinding attacks from browser pages. |
| Container | Built in | A distroless image with no shell, running as a non-root user with nothing to write. The default compose.yaml uses a read-only root filesystem, cap_drop: [ALL] and no-new-privileges. |
Why the switch matters more than usual
Section titled “Why the switch matters more than usual”Many APIs let you create a read-only key. Octopus doesn’t: the API key can do everything your login can through the API. So OCTOPUS_ALLOW_WRITES is enforced by octopus-mcp, not by Octopus. It still means a lot, because the model can only call tools that exist, but a bug in octopus-mcp, or a raw GraphQL query if you enable raw, is the only thing between the model and those changes. Keep raw out of OCTOPUS_TOOLSETS unless you need it.
The API key
Section titled “The API key”- Keep it in
.env(not committed;.envis in.gitignoreand.dockerignore) or, better, a Docker secret withOCTOPUS_API_KEY_FILE. - Don’t paste it into a chat with the assistant. octopus-mcp never needs it from the model.
- The key is sent to
api.octopus.energyonly: as HTTP Basic auth for account REST requests, and toobtainKrakenTokento get a token. Kraken tokens are kept in memory and last about an hour. - If you think the key has leaked, regenerate it on the API access page. The old key stops working immediately. Update
.envand restart.
Recommended setups
Section titled “Recommended setups”Read-only (lowest risk, the default):
- Writes off
- Leave out
rawif you don’t need it - Set
MCP_AUTH_TOKEN, even on a home network
EV charging or Saving Sessions:
OCTOPUS_ALLOW_WRITES=true- Only the toolsets you use, for example
account,tariffs,intelligent, and leaverawout - Keep tool confirmations on in your MCP client, so you approve each change
- Remember that a bump charge usually costs the peak rate
Network exposure
Section titled “Network exposure”- Set
MCP_AUTH_TOKENto a long random value. - Publish the port only where it’s needed: on a LAN address, or on
127.0.0.1behind a reverse proxy. - Never expose port 8080 directly to the internet. If traffic crosses a network you don’t trust, put TLS in front of it. See Deployment. Prefer a VPN to a public endpoint.
- Set
MCP_ALLOWED_HOSTSto the hostname clients use. - The server only needs outbound HTTPS to
api.octopus.energyandapi.backend.octopus.energy. If your firewall allows, restrict it to those.
Checklist
Section titled “Checklist”-
MCP_AUTH_TOKENis set to a long random value (openssl rand -hex 32). - The port is only reachable from machines that need it, or published on
127.0.0.1behind a proxy. - TLS terminates at a reverse proxy if traffic crosses an untrusted network. Prefer a VPN to a public endpoint.
- Writes are only enabled if you need them.
-
OCTOPUS_TOOLSETSlists only the toolsets you use, andrawis left out unless needed. - The API key is in a secret or an
.envfile that isn’t committed or shared. - The image is pinned to a version, and you update when security releases come out (watch the repository’s releases).