anker-solix-mcp
Click on "Install 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., "@anker-solix-mcpwhat is my current solar power production?"
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.
Anker Solix MCP Server
An MCP (Model Context Protocol) server that exposes data from an Anker Solix solar setup — Solarbank, expansion battery packs, and Smartmeter — as tools an LLM agent (Claude Desktop, Claude Code, or any other MCP host) can call directly. Ask things like "how much solar power are we producing right now?" or "what's the battery state of charge?" and have the assistant fetch live numbers instead of you opening the Anker app.
Built against and tested with a Solarbank 2 E1600 Pro + 1600 expansion battery pack + Anker Smartmeter, but the tools are written generically enough to work with any Solix devices linked to your Anker account.
⚠️ Unofficial. This project talks to Anker's cloud API via the reverse-engineered, community-maintained
anker-solix-apilibrary (the same one behind the Home Assistant Anker Solix integration). It is not affiliated with or endorsed by Anker Innovations, and Anker can change their API at any time and break this.
Contents
Related MCP server: emsesp-mcp-server
How this fits together
MCP (Model Context Protocol) is a small, open protocol for connecting an LLM application ("host", e.g. Claude Desktop or Claude Code) to external tools and data. The pieces:
MCP host — the chat application (Claude Desktop, Claude Code, etc). It reads the model's requests to call a tool, invokes the tool, and feeds the result back into the conversation.
MCP server — this project. A small program that declares a set of tools (name, description, input schema, and an implementation) and speaks the MCP protocol over a transport.
Transport — how the host and server talk. This server supports two:
stdio (the default) — the host launches it as a subprocess and exchanges JSON-RPC messages over its stdin/stdout. No network port, no auth handshake, the host manages the process lifecycle. This is what you want for Claude Desktop/Claude Code on the same machine (see Connecting to an MCP client).
streamable-http — the server instead listens on a TCP port and speaks MCP over HTTP (with SSE for streaming responses), so it can run as a long-lived, independently-deployed service that one or more remote MCP hosts connect to (see Running over HTTP).
┌─────────────────┐ JSON-RPC over stdio ┌───────────────────────┐ HTTPS ┌──────────────┐
│ MCP host │ ─────────────────────▶ │ anker-solix-mcp │ ────────▶ │ Anker cloud │
│ (Claude Desktop, │ ◀───────────────────── │ (this server, a │ ◀──────── │ API │
│ Claude Code, …) │ tool calls/results │ subprocess) │ data │ (unofficial) │
└─────────────────┘ └───────────────────────┘ └──────────────┘Within the server, each tool is just a Python async function decorated
with @mcp.tool(). The official Python MCP SDK's
FastMCP class turns the function's type hints and docstring into the JSON
schema and description the model sees — you write plain Python, the protocol
plumbing (schema generation, JSON-RPC framing, transport) is handled for you.
Repository structure
anker-solix-mcp/
├── pyproject.toml # package metadata, dependencies, console-script entry point
├── uv.lock # locked, reproducible dependency versions (uv-managed, committed)
├── .python-version # pins the interpreter uv uses/installs for this project (3.12)
├── .env.example # template for Anker account credentials
├── src/
│ └── anker_solix_mcp/
│ ├── server.py # builds the FastMCP app, registers tool modules, runs stdio or HTTP transport
│ ├── config.py # loads Settings (credentials, refresh interval, transport) from the environment
│ ├── client.py # AnkerSolixClient: lazy auth + refresh-throttled wrapper around AnkerSolixApi
│ ├── util.py # sanitize() (credential redaction), filter_devices() (heuristic type filter)
│ └── tools/
│ ├── sites.py # list_sites, get_site_overview
│ ├── devices.py # list_devices, get_device
│ ├── solarbank.py # list_solarbanks, get_solarbank_status, get_solarbank_schedule
│ ├── smartmeter.py # list_smartmeters, get_smartmeter_status
│ ├── energy.py # get_energy_statistics
│ └── maintenance.py # refresh_data, get_account_info
└── tests/
├── test_util.py # redaction / filtering unit tests
└── test_server.py # smoke-tests the assembled server against a fake client (no network)Each tools/*.py module exposes one register(mcp, client) -> None function
that attaches its tools to the shared FastMCP instance, closing over a
shared AnkerSolixClient. server.py is just the assembly point — this
keeps each domain's tools in one place and makes it easy to add a new file
for a new domain (see Extending).
Prerequisites
uv— used for everything (dependency management, virtualenv creation, running the server and tests). Install it withcurl -LsSf https://astral.sh/uv/install.sh | shor see the uv install docs.An Anker account with at least one Solix system registered in the Anker app.
Nothing else — you don't need Python preinstalled. This project pins Python 3.12 (required by the upstream
anker-solix-apilibrary) via.python-version/requires-python, anduvwill transparently download that exact interpreter the first time you run auvcommand here if it's not already on your machine.
Installation
git clone <this-repo-url> anker-solix-mcp
cd anker-solix-mcp
uv syncuv sync reads pyproject.toml + the committed uv.lock, downloads Python
3.12 if needed, creates a project-local .venv/, and installs every
dependency (including the dev-only ones like pytest, from the dev
dependency group) at the exact locked versions. Nothing needs activating —
every command below is run through uv run ..., which transparently uses
that .venv.
anker-solix-api isn't published on PyPI, so it's pulled straight from its
GitHub repo (see the anker-solix-api @ git+https://... entry in
pyproject.toml, pinned to a commit in uv.lock) — uv supports Git
dependencies natively, no extra configuration needed.
If you ever change a dependency in pyproject.toml by hand, run uv lock to
update uv.lock to match (or use uv add <package> / uv remove <package>,
which update both files for you in one step).
Configuration
Copy the example env file and fill in your Anker account credentials (the same ones you use to log into the Anker mobile app):
cp .env.example .env
$EDITOR .envVariable | Required | Description |
| yes | Anker account email |
| yes | Anker account password |
| no | Two-letter country code used at signup (default |
| no | Minimum seconds between automatic data refreshes (default |
| no | Default site ID, if you have more than one Anker Solix system |
| no |
|
| no | Bind address for HTTP transports (default |
| no | Bind port for HTTP transports (default |
| no | HTTP path the MCP endpoint is mounted at (default |
Credentials are only ever read from the environment/.env file and used to
authenticate against Anker's own API — nothing is sent anywhere else. Tool
outputs are also passed through a redaction step (see Design
notes) so tokens/passwords can't leak into a conversation
even if they show up in a raw API response.
Never commit your .env file. It's already listed in .gitignore.
Running the server standalone
Before wiring this into an MCP host, it's worth checking it actually talks to your account. The MCP Python SDK ships an inspector UI for exactly this:
uv run mcp dev src/anker_solix_mcp/server.pyThis opens the MCP Inspector in your browser, where you can call each tool by hand and see the raw JSON it returns. Alternatively, just run the server directly (it will sit waiting for stdio input, which is expected):
uv run anker-solix-mcpConnecting to an MCP client
Claude Code
claude mcp add anker-solix -- uv --directory /absolute/path/to/anker-solix-mcp run anker-solix-mcpOr add it by hand to your Claude Code MCP settings:
{
"mcpServers": {
"anker-solix": {
"command": "uv",
"args": ["--directory", "/absolute/path/to/anker-solix-mcp", "run", "anker-solix-mcp"]
}
}
}Claude Desktop
Add the same block to claude_desktop_config.json (Settings → Developer →
Edit Config), then restart Claude Desktop.
Any other MCP host
Any host that can launch a local process and speak MCP-over-stdio can use
this server — point it at uv run anker-solix-mcp (or the equivalent
python -m anker_solix_mcp inside the project's virtualenv) with the working
directory set to this repo (or ANKER_EMAIL/ANKER_PASSWORD/etc. exported
directly in the host's environment instead of a .env file).
Running over HTTP
Everything above assumes stdio: the MCP host runs on the same machine and launches this server itself. If instead you want to run the server as a standalone, long-lived service — e.g. on a home server/NAS/Raspberry Pi near your network, with one or more MCP hosts (a laptop, a phone client, several people) connecting to it remotely — use the streamable-http transport instead.
Starting it
ANKER_MCP_TRANSPORT=streamable-http \
ANKER_MCP_HOST=127.0.0.1 \
ANKER_MCP_PORT=8000 \
uv run anker-solix-mcpOr set the same variables in your .env file (see .env.example). The
process now behaves like a normal web server: it stays running, logs to
stderr, and listens on http://<host>:<port><path> (default path /mcp)
until you stop it (Ctrl+C or SIGTERM — the Anker API session is closed
cleanly on shutdown).
Point an HTTP-capable MCP client at that URL, e.g. for Claude Code:
claude mcp add --transport http anker-solix http://127.0.0.1:8000/mcpor in a client's MCP settings JSON:
{
"mcpServers": {
"anker-solix": {
"type": "http",
"url": "http://127.0.0.1:8000/mcp"
}
}
}What changes vs. stdio, and what to consider
Moving from stdio to HTTP turns this from "a subprocess only the host that launched it can see" into "a network service" — several things that stdio gave you for free now become your responsibility:
Exposure / access control. Anyone who can reach the port can call every tool here — read-only, but that still means your Solix site/device data and Anker account info (see Available tools) are readable by whoever connects.
anker-solix-mcpitself ships no authentication for HTTP. Don't bindANKER_MCP_HOSTto0.0.0.0(or otherwise expose the port to an untrusted network) without adding an auth layer in front — see below.Recommended: keep it off the public internet. The realistic setups for a personal project like this, roughly in order of effort:
Loopback only (
ANKER_MCP_HOST=127.0.0.1, the default) if the MCP host runs on the same machine — gets you nothing over stdio, so prefer stdio in that case.Private network / VPN — bind to your LAN interface (or
0.0.0.0) but only reach it over a VPN you control (Tailscale, WireGuard) or your home LAN, never a port forwarded to the public internet.Reverse proxy in front (Caddy, nginx, Traefik) if you do need access from outside your network: terminate TLS there (streamable-http has no TLS of its own) and add an auth layer — HTTP basic auth or a bearer-token check in front is enough for a single-user tool, since
mcp[cli]'sFastMCPalso supports plugging in a realTokenVerifier/OAuth provider (FastMCP(auth=...)) if you want the MCP-native auth flow instead.
Single process, not a fleet.
AnkerSolixClientthrottles refreshes and authenticates lazily using in-process state (anasyncio.Lockand a last-refresh timestamp — seeclient.py). That only works correctly within one process: don't run multipleuv run anker-solix-mcpinstances or a multi-worker server (e.g.uvicorn --workers N) in front of the same Anker account, or the refresh throttle stops meaning anything and you risk hammering Anker's API from several unsynchronized processes at once. One process comfortably serves many concurrent MCP clients/sessions.Keep it running. Unlike stdio (where the host starts/stops the process for you), you're now responsible for the process lifecycle: run it under a process supervisor — a
systemduser/system service, a Docker container withrestart: unless-stopped,tmux/screenfor a quick manual setup — so it survives reboots and crashes and its logs (it logs to stderr) go somewhere you can check.Credentials still come from the environment. Nothing changes here —
ANKER_EMAIL/ANKER_PASSWORD/etc. are still read once at process start (from the environment or.envin the working directory). Make sure whatever supervises the process sets them the same way you would for stdio; there's no per-request credential handling to worry about since this is still a single-account tool, not a multi-tenant service.ssetransport is also available (ANKER_MCP_TRANSPORT=sse) for older MCP clients that predate streamable-http, but it's deprecated in the MCP spec — preferstreamable-httpunless you specifically need it.
Available tools
Tool | Description |
| List every Anker power system ("site") on the account, keyed by site ID. |
| Full cached detail record for one site (power-flow summary, if reported). |
| List every device (Solarbank, expansion pack, Smartmeter, …) keyed by serial number. |
| Full, unfiltered cached detail record for one device. |
| Devices that look like Solarbanks / expansion battery packs. |
| Battery SoC, solar input, output power, charge/discharge power, temperature, etc. |
| The configured charge/discharge schedule / output-power plan, if present. |
| Devices that look like Anker Smartmeters. |
| Current grid import/export power and other reported fields. |
| Fresh (non-cached) energy totals: production, charge/discharge, grid import/export, home usage. |
| Force an immediate refresh of all cached data, bypassing the throttle. |
| Basic Anker account info (nickname, etc.), credentials redacted. |
All tools are read-only — none of them changes a device setting. That's a deliberate scope choice (see Design notes and Extending if you want to add control tools yourself).
Design notes
Why tools return mostly raw, pass-through data. anker-solix-api talks to
an undocumented private API — its cached data's exact shape varies by device
model and firmware, and can change without notice. Rather than hardcoding
field names that might not match your specific setup (and silently dropping
data that doesn't fit an assumed schema), most tools return the underlying
library's cached dict close to as-is, scoped to the relevant site/device.
Modern LLMs are good at reading arbitrary JSON and picking out the field the
user asked about, so this trades a bit of "raw JSON in the transcript" for
resilience against upstream schema drift. list_solarbanks /
list_smartmeters apply a best-effort heuristic filter (matching known model
codes / type strings) but fall back to returning everything if nothing
matches, rather than silently returning an empty result.
Redaction. Every tool response is passed through util.sanitize(), which
recursively redacts any dict key that looks like a credential (password,
token, secret, cookie, auth_*, …) before it's returned. This is
defense-in-depth on top of never printing credentials directly — the account
cache in particular could plausibly carry session-related fields.
Refresh throttling. AnkerSolixClient.refresh() is throttled to
ANKER_REFRESH_SECONDS (default 60s) so a burst of tool calls within one
conversation turn costs a single round trip to Anker's API, not one per tool.
get_energy_statistics and refresh_data intentionally bypass the throttle,
since "give me the latest number" is the most common reason to call them.
Lazy authentication. The Anker API client and its HTTP session are only
created on first use (inside AnkerSolixClient._ensure_api), not at import
time — so importing the server module, or running its test suite, never
makes a network call or requires credentials to be present.
Development
uv sync # dev dependency group (pytest, pytest-asyncio) is included by default
uv run pytesttests/test_server.py builds the MCP server against a small fake client (see
FakeAnkerSolixClient), so the test suite runs with no Anker credentials and
no network access.
To add or upgrade a dependency, prefer uv add <package> (or uv add --group dev <package> for a dev-only tool) over hand-editing pyproject.toml — it
resolves and updates uv.lock for you in the same step. Run uv lock --upgrade occasionally to pick up new compatible versions, including a newer
commit of anker-solix-api if the upstream library has moved on.
Extending
To add a new tool:
Add an
async deffunction to an existingtools/*.pymodule (or create a new module for a new domain), decorated with@mcp.tool()inside that module'sregister(mcp, client)function.Write a clear docstring — the MCP client (and, in turn, the model) sees it as the tool's description, so be explicit about what the tool returns and when to call it.
If it's a new module, register it in
build_server()inserver.py.Add a test in
tests/usingFakeAnkerSolixClient(extend it if your tool needs data the fake doesn't provide yet).
To add a device-control tool (e.g. changing the Solarbank's output power
or charge schedule via AnkerSolixApi.set_station_parm /
set_device_attributes), consider gating it behind explicit user
confirmation in your MCP host, since unlike the read-only tools here, a
mistaken call would actually change how your hardware behaves.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/gkoenig/anker-solix-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server