Skip to main content
Glama
evaconnect-mcp

evaconnect-mcp

by ca11mebaraka

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/*.pth

Then 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 server

  • evaconnect-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 SMS

When the SMS arrives:

from evaconnect import EvoluteClient

with EvoluteClient() as client:
    client.sign_in("00000000000", "000000")  # phone, SMS code

That 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 5
from 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 vehicles

MCP (Cursor)

stdio server. Tools (read-only):

Tool

What it returns

evolute_status

Charge, climate, doors, online. Geo hidden unless include_pii

evolute_vehicles

List; VIN/IMEI masked unless include_pii

evolute_trips

Last N trips; no addresses/track

evolute_trip

One trip; track only if include_track=true

evolute_charge

Current charge session (or empty)

evolute_auth_status

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.

pytest

Grafana 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 telemetry.raw JSONB

Движение

Odometer timeseries, ignition/park/signal

Служебные сенсоры

Fuel % / firmware / settings (often unused on EV)

Поездки

Extra table (battery_first/last) and distance/consumption chart. Overview trips title is MSK from start_date/end_date

Poller

Cycle duration and errors

Trip addresses and coordinates are not stored. See deploy/README.md (RU).

Spec gaps (explicit parameters, no guessing)

  • Phone / phoneCountry format is unknown — pass them as strings.

  • Trip sort.by / dir default to live-confirmed DATE / DESC (DURATION / DISTANCE and ASC are also valid).

  • distance units (m vs km) are unknown — raw int, 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-Zone header 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.

The unofficial API description under api/ is CC0-1.0.

Available Tools

6 tools
evolute_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

    B3.4/5.0

    Scored across 6 tools

    Disambiguation4/5

    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.

    Naming Consistency5/5

    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.

    Tool Count5/5

    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.

    Completeness4/5

    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

    ActivityStale
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      A
      quality
      D
      maintenance
      Provides 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.
      10
      MIT
    • A
      license
      A
      quality
      B
      maintenance
      Enables 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.
      9
      55 npm
      4
      MIT
    • A
      license
      A
      quality
      C
      maintenance
      Provides 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.
      12
      MIT
    • A
      license
      A
      quality
      B
      maintenance
      Enables 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.
      12
      MIT