tesla-mcp
Provides tools for interacting with a Tesla vehicle through Tesla's Fleet API, including listing vehicles, checking status without waking the car, waking the vehicle, sending signed door-lock commands, checking nightly lock status, and viewing recent audit logs.
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., "@tesla-mcpis my Tesla locked, and how much battery does it have?"
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.
tesla-mcp
A private Model Context Protocol server for one Tesla owner, running on Cloudflare Workers. It lets an assistant (Claude, Grok in the car, or any Streamable HTTP MCP client) check the car and lock it, and it locks the car automatically every night.
Lock is sent as a signed Vehicle Command Protocol message (the VCSEC domain), so it works on vehicles that require Tesla's command signing. The signer is a WebCrypto port checked byte for byte against the owner's production Python implementation.
Status: owner-only MVP. One owner, one static bearer token, one Tesla account. Multi-user sign-in with Tesla OAuth is planned; the auth and storage seams are already in place for it.
Tools
Tool | Kind | What it does |
| read | Cars on the account with id, name, and online/asleep/offline. |
| read | Online or asleep; when online: locked, open doors/trunks/windows, battery, range, charging, temperatures, climate, Sentry Mode, odometer. Never wakes the car. No location. |
| command | Wake the car. |
| command | Lock the doors with a signed command. Wakes the car and retries if needed. |
| read | Whether the nightly lock is on, its local time and zone, next run, last result. |
| read | Newest audit log entries (default 20). |
Related MCP server: Tessie MCP Server
Safety model
Confirmation required. Every state-changing tool refuses to act unless called with
confirm: true, and acceptsdryRun: trueto describe the action without contacting the car. Refusals are audited.No dangerous commands. Unlock, remote start, opening trunks/frunk/windows, valet/PIN/speed-limit changes, HomeLink, and data erase are not implemented. A single gate (
DANGEROUS_COMMANDS_ENABLED, default"false") must be explicitly enabled before any such tool could even be registered.Never wakes implicitly. Status reads report "asleep" instead of waking the car. Only
tesla_wake,tesla_lock, and the nightly lock wake it.Explicit command allowlist. The signer can only build the commands it names (today: door lock). It is not a generic vehicle-command proxy.
Secrets stay secret. Tesla tokens are stored AES-256-GCM encrypted in a Durable Object. Tokens, keys, and raw Tesla responses are never logged or written to the audit log.
Fail closed. No
MCP_BEARER_TOKENmeans every/mcprequest is refused. A command key that does not match the published public key refuses to sign.
Nightly lock
At NIGHTLY_LOCK_TIME in NIGHTLY_LOCK_TIMEZONE (default 22:00 America/New_York, correct across daylight saving
changes), a Durable Object alarm sends the signed lock. If the car is asleep or offline it is woken, polled until
online (up to about 90 seconds), and the lock is retried, up to 4 attempts in total. An already locked car counts as
success. Failures Tesla marks as not retryable stop at once. If a lock response is lost, or the car only
acknowledges the command without confirming it ran, the car's lock state is checked instead of sending the lock
again. The whole run stops starting new attempts after 7 minutes, well inside the 15-minute limit Cloudflare gives an
alarm. A night that finished never runs again. A run interrupted part way (for example, the Durable Object was
restarted) is resumed up to 3 times, within 3 hours of the scheduled time, and a resumed run checks whether the car
is already locked before sending anything. After that it is audited as missed or abandoned. If an outage delays the
alarm past the next night's lock time, that night still runs (within the same 3-hour window) instead of being
skipped. Every run is audited. A cron trigger every 15 minutes keeps the alarm armed; it does nothing else, so right
after a first deploy tesla_nightly_lock_status shows no next run until the first cron tick.
Self-hosting
You need a Tesla developer account, a Cloudflare account, and a domain you control (Tesla fetches your public key from it). Node 22 or newer.
Create a Tesla developer application at developer.tesla.com. Set the allowed origin to
https://<your-domain>and the redirect URI tohttps://<your-domain>/callback. Request the scopesopenid offline_access vehicle_device_data vehicle_cmds.Generate a P-256 command key somewhere outside this repository (
*.pemandkeys/are gitignored, but keep the private key off disk where you can):openssl ecparam -name prime256v1 -genkey -noout -out private-key.pem openssl ec -in private-key.pem -pubout -out public-key.pemPublish the public key. Put the contents of
public-key.peminTESLA_PUBLIC_KEY_PEMinwrangler.jsonc(newlines as\n). After deploying, it is served athttps://<your-domain>/.well-known/appspecific/com.tesla.3p.public-key.pem. If your account is outside North America, changeTESLA_FLEET_BASE_URLto your region's Fleet API host.Set secrets (see
.dev.vars.examplefor what each one is):npx wrangler secret put MCP_BEARER_TOKEN npx wrangler secret put TESLA_CLIENT_ID npx wrangler secret put TESLA_CLIENT_SECRET openssl pkcs8 -topk8 -nocrypt -in private-key.pem -outform DER | base64 | tr -d '\n' \ | npx wrangler secret put TESLA_COMMAND_PRIVATE_KEY_PKCS8_B64 openssl rand -base64 32 | npx wrangler secret put TOKEN_ENCRYPTION_KEY npx wrangler secret put TESLA_BOOTSTRAP_REFRESH_TOKEN # see step 7 npx wrangler secret put TESLA_VEHICLE_ID # optionalDeploy with
npm ci && npx wrangler deploy, then attach your domain to the Worker (Workers & Pages → your Worker → Domains & Routes → Custom domain). You can smoke-test/healthzon your workers.dev URL first, but Tesla registration needs your own domain.Register as a Tesla partner for your domain (once per region), using a partner token:
PARTNER_TOKEN=$(curl -s -X POST https://fleet-auth.prd.vn.cloud.tesla.com/oauth2/v3/token \ -d grant_type=client_credentials -d client_id="$TESLA_CLIENT_ID" -d client_secret="$TESLA_CLIENT_SECRET" \ -d scope="openid vehicle_device_data vehicle_cmds" \ -d audience=https://fleet-api.prd.na.vn.cloud.tesla.com | jq -r .access_token) curl -s -X POST https://fleet-api.prd.na.vn.cloud.tesla.com/api/1/partner_accounts \ -H "Authorization: Bearer $PARTNER_TOKEN" -H 'Content-Type: application/json' \ -d '{"domain":"<your-domain>"}'Get a refresh token for your account. Browser sign-in is not built yet. Complete Tesla's OAuth authorization-code flow once (for example with Tesla's documented flow or a tool you trust), then store the refresh token with
wrangler secret put TESLA_BOOTSTRAP_REFRESH_TOKEN. It seeds the encrypted token store once; Tesla rotates refresh tokens, and the Worker keeps the newest. If Tesla later rejects it, the server reportsreauth_requiredand stops retrying until you set a new bootstrap token.Pair the virtual key with the car. On the phone with the Tesla app, open
https://tesla.com/_ak/<your-domain>and approve the key. Signed commands fail with "pairing required" until this is done.Connect your MCP client to
https://<your-domain>/mcpwith the headerAuthorization: Bearer <MCP_BEARER_TOKEN>.
Development
npm ci
npm run check # typecheck, Biome lint, tests
npm run deploy:dry # bundle without deployingTests run in the Workers runtime against a simulated Tesla (Fleet API, OAuth, and a vehicle that performs the real
ECDH handshake and verifies every signature). All test credentials are generated at runtime. The VCSEC vectors in
test/vcp-vectors.test.ts come from scripts/vcsec_vectors.py.
bash conformance/run.sh (needs Go) checks the shared vectors in test/vectors/vcsec-lock.json against Tesla's
official Go implementation at a pinned commit of teslamotors/vehicle-command. It covers key derivation, the
handshake, the signed lock, the response request hash, and AES-GCM response decryption. CI runs it as the
go-conformance job.
License
MIT. See LICENSE.
This server cannot be deployed
Maintenance
Related MCP Connectors
- mytesla.ioOAuthio.mytesla
Control your Tesla from your AI assistant - climate, charging, access, and security.
Control your Tesla - wake it, warm it up, unlock and more. Get your developer token at https://Infoseek.ai/mcp. Also requires your own Tesla developer token which is tied to your car/fleet.
- AskMyEVOAuthcom.askmyev
Tesla data for your AI: battery, range, charging, tires, alerts, history. Controls off by default.
Tesla Fleet API for AI: send navigation destinations, read battery and location, run car commands.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables control and monitoring of Tesla vehicles through the Tessie API, providing access to vehicle state (battery, location, climate) and commands (lock/unlock, climate control, navigation) with support for both local and Cloudflare Worker deployment.11MIT
- AlicenseAqualityDmaintenanceEnables AI assistants to control and monitor Tesla vehicles via natural language through the Tessie API, supporting battery, climate, security, charging, and more.611MIT
- AlicenseNot gradedqualityDmaintenanceEnables control and monitoring of Tesla vehicles via the Tessie API, providing state and command tools for climate, locks, charging, and navigation.MIT
- AlicenseAqualityAmaintenanceConnects a MyToyota or MyLexus Europe account to Claude and other MCP clients, enabling natural-language access to fuel, range, location, trips, health, climate, charging data, and remote commands such as lock, climate, and charging.2667 PyPI1MIT