-
Notifications
You must be signed in to change notification settings - Fork 19
Development
git clone https://github.com/cobanov/teslamate-mcp.git
cd teslamate-mcp
cp env.example .env # set DATABASE_URL
uv sync # install with dev dependenciesuv run ruff check src tests # lint
uv run ruff format src tests # format
uv run pytest # tests
uv run teslamate-mcp list-tools # what the registry discoveredThe suite mixes fast unit tests with integration tests that spin up a real PostgreSQL through testcontainers. Docker-backed tests skip automatically when no daemon is reachable, so uv run pytest works on a laptop without Docker — you just cover less.
If you use a non-standard Docker socket (OrbStack, Colima, rootless Docker), point testcontainers at it:
DOCKER_HOST=unix://$HOME/.orbstack/run/docker.sock uv run pytestIntegration tests seed a miniature TeslaMate-shaped schema and run every bundled query against it, so a query that references a column that does not exist fails in CI rather than in someone's conversation.
src/teslamate_mcp/
├── cli.py # click entry points: stdio, http, gen-token, list-tools
├── server.py # MCPServer factory, lifespan, connection pool ownership
├── config.py # pydantic-settings; every env var lives here
├── db.py # pool construction and the three execution paths
├── schema.py # information_schema introspection, cached at startup
├── auth.py # bearer middleware (timing-safe, /health exempt)
├── prompts.py # the six workflow prompts
├── resources.py # teslamate:// catalog resources
├── telemetry.py # optional OpenTelemetry wiring
├── apps/ # self-contained HTML for the MCP Apps charts
├── queries/ # the .sql + .toml pairs — where most changes go
└── tools/
├── registry.py # discovery, param validation, handler factory
├── custom_sql.py # run_sql and its read-only guards
├── schema_tool.py # get_database_schema
├── apps_ui.py # spec-driven MCP Apps registration
└── charging_write.py # the opt-in write tool
Knowing which one you are on matters:
| Function | Used by | Guards |
|---|---|---|
fetch_all |
Predefined queries, schema introspection | Connection-level STATEMENT_TIMEOUT_MS
|
fetch_readonly |
run_sql |
READ ONLY transaction, forced rollback, QUERY_TIMEOUT_MS, lock_timeout
|
execute_write |
set_charging_cost only |
Commits. Gated by config; the column grant is the real boundary |
Never route user-supplied SQL through fetch_all or execute_write.
See Writing Queries — it needs no Python.
Tagging v* triggers .github/workflows/release.yml, which builds a multi-arch (linux/amd64, linux/arm64) image, pushes it to GHCR, and opens a GitHub release.
# bump version in pyproject.toml and add a CHANGELOG entry first
git tag -a v0.10.0 -m "v0.10.0"
git push origin v0.10.0