evaconnect-mcp
This server is a read-only MCP interface to your Evolute vehicle account, exposing telemetry and trip data without sending commands.
evolute_status — Get current vehicle telemetry: charge, climate, doors, and online status; coordinates hidden unless
include_piiis enabled.evolute_vehicles — List vehicles on the account; VIN/IMEI masked unless
include_piiis true.evolute_trips — Retrieve recent trips for a vehicle, with optional limit, offset, sorting, and PII inclusion; addresses and track are omitted.
evolute_trip — Fetch a single trip by travel ID and start time; include track points with
include_trackand addresses withinclude_pii.evolute_charge — Show the current charge session, or an empty result if not charging.
evolute_auth_status — Check whether the stored session looks valid, without exposing raw tokens.
It intentionally does not provide OTP login, command sending, or vehicle control.
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., "@evaconnect-mcp what's my car's current charge and doors status?"
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.
evaconnect
Typed Python client and stdio MCP server for the Evolute companion API
(https://app.evassist.ru). Own account / own vehicle only.
Read telemetry (charge, climate, doors, online) and recent trips without the official Android app. Vehicle commands are not implemented — the command channel is unconfirmed.
Install
Python 3.12+.
cd evaconnect
python3.12 -m venv .venv
source .venv/bin/activate
pip install ".[dev]"Do not use pip install -e on Python 3.14 / macOS. Hatchling marks the
.pth as Finder-hidden; 3.14 then skips it. import evaconnect hits a
namespace leftover in site-packages/evaconnect (often only schema.sql),
and the CLI dies:
ModuleNotFoundError: No module named 'evaconnect'
ModuleNotFoundError: No module named 'evaconnect.cli'Install a regular wheel (pip install . or pip install ".[dev]"). If you
already used -e, either reinstall without it, or:
chflags nohidden .venv/lib/python*/site-packages/*.pthThen evolute --help should print the subcommands. Repeating pip install -e
puts the hidden flag back.
Entry points after install:
evolute— small CLI (status,trips,vehicles,info)evaconnect-mcp— stdio MCP serverevaconnect-poller— write telemetry/trips to Postgres for Grafana
Remote poller + Postgres next to an existing Grafana: see deploy/README.md
(RU).
Grafana dashboard JSON: deploy/grafana/dashboards/evolute.json
(folder Evolute, uid evaconnect-evolute, timezone Europe/Moscow).
Unofficial reverse-engineered HTTP spec (CC0, not vendor docs): api/README.md (RU).
Related MCP server: Rivian MCP
Auth
There is no password. The official app logs in with an SMS code. evaconnect
does the same: one SMS, then a token pair. The CLI has no login
command (and MCP never requests OTP). Use a short Python snippet.
1. Get tokens
phone / phoneCountry are whatever the official app sends. The vendor does
not document the mask; a live login used an 11-digit number (country code +
national number, no +) and a two-letter phoneCountry.
from evaconnect import EvoluteClient
phone = "00000000000"
phone_country = "XX"
with EvoluteClient() as client:
client.get_info() # optional; field is capcha, not captcha
client.request_otp(phone, phone_country) # sends one SMSWhen the SMS arrives:
from evaconnect import EvoluteClient
with EvoluteClient() as client:
client.sign_in("00000000000", "000000") # phone, SMS codeThat writes ~/.config/evolute/credentials.json (chmod 600):
{
"accessToken": "<YOUR_TOKEN>",
"refreshToken": "<YOUR_REFRESH_TOKEN>",
"userId": "",
"userToken": "",
"widgetId": "",
"carId": null
}Override the path with EVOLUTE_CREDENTIALS. carId is optional: if empty,
the client uses the first vehicle on the account. Set it after
evolute vehicles if you have more than one car.
Do not commit this file, the phone number, VIN, IMEI, or coordinates.
2. Use the tokens
Later calls send header access-token: <accessToken>, not
Authorization: Bearer. The client loads the file automatically. Env vars
EVOLUTE_ACCESS_TOKEN / EVOLUTE_REFRESH_TOKEN / EVOLUTE_CAR_ID fill
empty fields only — they do not override tokens already in the file.
evolute vehicles
evolute status
evolute trips -n 5from evaconnect import EvoluteClient
with EvoluteClient() as client:
client.refresh() # optional; also happens automatically on HTTP 401
print(client.list_vehicles())
print(client.get_telemetry(car_id=client.default_car_id()))curl (same headers the Android client sends):
TOKEN=$(python3 -c "import json,pathlib; p=pathlib.Path.home()/'.config/evolute/credentials.json'; print(json.loads(p.read_text())['accessToken'])")
curl -sS 'https://app.evassist.ru/id-service/user' \
-H "access-token: $TOKEN" \
-H 'accept: application/json' \
-H 'x-device: android' \
-H 'x-app: mobile' \
-H 'x-app-version: 5.1.22 (740)'Poller / Grafana: copy that credentials.json onto the server after the
last local use (refresh rotates refreshToken). See
deploy/README.md (RU).
MCP: point EVOLUTE_CREDENTIALS at the file, or leave tokens out of
mcp.json so the default path is used. Do not put live tokens in git.
When a data request returns 401, the client refreshes once, writes the
new pair back to the file, and retries. If refresh itself returns 401,
the pair is dead — run sign_in again. HTTP details:
api/docs/authentication.md
(RU).
Library
from evaconnect import EvoluteClient
with EvoluteClient() as client:
client.refresh()
me = client.me()
cars = client.list_vehicles() # id, plate, model; VIN/IMEI not in repr
car = client.get_vehicle(cars[0].id)
tel = client.get_telemetry(car_id=car.id) # or imei=…
session = client.get_charge_session() # may be None
trips = client.list_trips(car.id, limit=5, offset=0)
trip = client.get_trip(car.id, trips.rows[0].id, trips.rows[0].segment_start_time)get_telemetry accepts an IMEI or a mongo car _id (24 hex chars) and
resolves IMEI when needed. Those two IDs are not interchangeable.
send_command exists only as a stub and always raises NotImplementedError.
CLI
evolute info # GET /id-service/info (no token)
evolute status
evolute trips -n 5
evolute vehiclesMCP (Cursor)
stdio server. Tools (read-only):
Tool | What it returns |
| Charge, climate, doors, online. Geo hidden unless |
| List; VIN/IMEI masked unless |
| Last N trips; no addresses/track |
| One trip; track only if |
| Current charge session (or empty) |
| Session present/valid; no raw tokens |
There is no request_otp and no command-sending tool.
Cursor mcp.json example (~/.cursor/mcp.json or project .cursor/mcp.json):
{
"mcpServers": {
"evaconnect": {
"command": "/Users/nmel/Documents/Projects/evaconnect/.venv/bin/evaconnect-mcp",
"env": {
"EVOLUTE_ACCESS_TOKEN": "",
"EVOLUTE_REFRESH_TOKEN": "",
"EVOLUTE_CAR_ID": ""
}
}
}
}If the venv is on PATH, "command": "evaconnect-mcp" is enough.
Default MCP output redacts VIN, IMEI, phone, tokens, and exact coordinates
(include_pii off). Do not poll telemetry faster than once per 5 seconds
(the client caches within that window).
Tests
Mocks only — tests never call production. GitHub Actions runs pytest and
Spectral on api/openapi.yaml.
pytestGrafana dashboard
Provisioned JSON: deploy/grafana/dashboards/evolute.json.
Datasource uid evaconnect-pg. Rows:
Row | Content |
Обзор | Original nine panels: Battery, Remaining range, Temperatures (cabin/outside/battery), 12V, Online, Central lock, Odometer, Poller heartbeat, Recent trips |
Сейчас | Ignition, park, charge gun, signal, climate target/fan, last snapshot, command catalog |
Зарядка | Charge-gun timeseries |
Климат | Coolant, climate target, fan |
Кузов | Doors, trunk, headlights from |
Движение | Odometer timeseries, ignition/park/signal |
Служебные сенсоры | Fuel % / firmware / settings (often unused on EV) |
Поездки | Extra table ( |
Poller | Cycle duration and errors |
Trip addresses and coordinates are not stored. See deploy/README.md (RU).
Spec gaps (explicit parameters, no guessing)
Phone /
phoneCountryformat is unknown — pass them as strings.Trip
sort.by/dirdefault to live-confirmedDATE/DESC(DURATION/DISTANCEandASCare also valid).distanceunits (m vs km) are unknown — rawint, no conversion.Access-token TTL is unknown — one auto-refresh on HTTP 401, no loop.
Charge-session body when charging is not fully specified. See api/docs/quirks.md (RU).
Time-Zoneheader is unused (not confirmed).
Full endpoint table and x-status markers: api/README.md
(RU).
License
MIT for the Python client, MCP server, and poller.
Available Tools
6 toolsevolute_auth_statusA
Whether a session looks valid. Never returns raw tokens.
Inputs: no named parameters. Returns: result
evolute_chargeA
Current charge session, if any. Empty when not charging.
Inputs: no named parameters. Returns: result
evolute_statusB
Telemetry of the default (or given) vehicle: charge, climate, doors, online. Coordinates are hidden unless include_pii is true.
Inputs: car_id, include_pii. Returns: result
evolute_tripC
One trip. Track points only if include_track=true. Addresses only if include_pii=true. start_time is segmentStartTime.
Inputs: travel_id (required), start_time (required), car_id, include_pii, +1 more. Returns: result
evolute_tripsB
Recent trips for the default (or given) vehicle. Addresses and track are omitted. Distance is a raw integer (units unknown).
Inputs: limit, car_id, offset, sort_by, +2 more. Returns: result
evolute_vehiclesA
List vehicles. VIN/IMEI are masked unless include_pii is true.
Inputs: include_pii. Returns: result
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 6 tools
Most tools are clearly distinct: vehicles, trips, trip, auth_status, and charge each target a separate resource. The only mild overlap is evolute_status including charge information while evolute_charge focuses on the active charging session, but the descriptions clarify the boundary.
All tools follow the same evolute_ noun pattern with snake_case. Singular/plural is used intuitively (trips vs trip), and the naming is predictable across the entire set.
Six tools is a well-scoped count for an EV telemetry and connectivity server. Each tool covers a meaningful read-only operation without unnecessary bloat.
The tool set covers the core read-only domain: vehicle listing, current status, recent trips, trip details, active charge session, and auth validation. Minor gaps exist such as no direct vehicle detail endpoint or historical charge sessions, but the main workflows are supported.
Maintenance
Related MCP Connectors
AI for your car: check charge, start climate, lock/unlock, open trunk via Tesla Fleet API. OAuth.
Operate one Evolution API (WhatsApp) instance: chats, history, sending, groups, settings.
Read-only access to a Zoopit account: orders, routes, fleet and live vehicle positions.
Operate a network of EV charge points over OCPP: status, sessions, tariffs, prices, remote commands
Related MCP Servers
- AlicenseAqualityDmaintenanceProvides access to Alpha ESS solar inverter and battery system data, enabling monitoring of energy statistics, real-time power data, and configuration of battery charging and discharge schedules through the Alpha ESS Open API.10MIT
- AlicenseAqualityBmaintenanceEnables read-only access to vehicle data via the unofficial Rivian GraphQL API, allowing users to monitor battery levels, OTA updates, and charging status. It provides tools to check vehicle state and user account information directly through Claude.955 npm4MIT
- AlicenseAqualityCmaintenanceProvides read-only access to a China-region Garmin Connect account, enabling retrieval of daily summaries, sleep, heart rate, HRV, training readiness, body battery, and activity data.12MIT
- AlicenseAqualityBmaintenanceEnables read-only access to BMW CarData for vehicle maintenance, tire pressure, and 12V battery status, with caching and local history to stay within the daily API quota.12MIT