Skip to main content
Glama
CMLabsLLC
by CMLabsLLC

betterkey-mcp

Model Context Protocol server that lets AI agents inspect and act on your BetterKey-connected vehicles.

Open-source bridge. You mint the key, you keep the control. The server never calls your vehicle's API directly; every request goes to BetterKey's existing /v1/* HTTP API over HTTPS, authenticated with an API key you mint in the BetterKey iOS app.

Tools

Six tools are exposed over stdio:

Tool

What it does

API-key scope required

list_vehicles

Lists your connected vehicles (id, make, model, color).

telemetry.read

get_vehicle_telemetry

Returns the latest windows/odometer/fuel/battery snapshot with per-signal oemUpdatedAt and an isStale flag.

telemetry.read

get_vehicle_capabilities

Identity + which signals have fresh data right now + known upstream quirks the agent should respect.

telemetry.read

lock_vehicle

Lock the vehicle. Destructive. The agent must obtain explicit human confirmation. Returns confirmation: "confirmed" or "unconfirmed".

vehicle.command

unlock_vehicle

Unlock the vehicle. Destructive, with the same confirmation and confirmation-status semantics as lock_vehicle.

vehicle.command

get_vehicle_location

Current OEM-reported location. Location-sensitive; coordinates are never logged by the server.

vehicle.command

Related MCP server: Tessie MCP Server

What it does not do

  • It does not read your Firestore directly.

  • It does not hold a vehicle-manufacturer OAuth token.

  • It does not call the vehicle manufacturer's API itself.

  • It does not expose any way to bypass BetterKey's ownership, subscription, or rate-limit checks. Those run server-side on every call.

Setup

1. Mint a BetterKey API key

Open the BetterKey app on iOS → Settings → API Keys → Create. Copy the bk_... secret immediately; it is shown only once.

Scopes. A key minted from the iOS app today holds telemetry.read + vehicle.command by default, enough to drive every tool here. If you'd rather keep this bridge read-only (Homebridge-style), mint the key via a direct POST /v1/account/api-keys with {"label":"...","scopes":["telemetry.read"]}. A read-only key calling a command tool returns a tool-level insufficient_scope error naming the missing scope.

2. Register with your MCP host

Claude Desktop. Edit ~/Library/Application Support/Claude/claude_desktop_config.json:

{
  "mcpServers": {
    "betterkey": {
      "command": "npx",
      "args": ["-y", "betterkey-mcp"],
      "env": {
        "BETTERKEY_API_KEY": "bk_..."
      }
    }
  }
}

Restart Claude Desktop. The six tools should appear in the tool palette.

3. Try it

  • "List my vehicles."

  • "What's the latest telemetry for <make>?"

  • "What can BetterKey tell me about <make> right now?"

  • "Lock <make>." The agent should confirm with you first; a confirmation: "unconfirmed" result means the lock command was accepted by BetterKey but the automaker's acknowledgement is unavailable (the lock may or may not have actuated).

  • "Where is <make>?" Returns latitude/longitude plus the OEM timestamp.

Environment

Variable

Required

Default

Description

BETTERKEY_API_KEY

yes

(none)

A bk_... secret from the BetterKey app. The server refuses to start without one.

BETTERKEY_API_BASE

no

https://betterkey.xyz

Point at https://staging.betterkey.xyz for staging, or http://localhost:8080 when developing against a local BetterKey backend.

Revoking access

Agent-host access to your vehicle data lasts only as long as the API key is valid. To revoke:

  1. In the BetterKey app → Settings → API Keys → delete the key.

  2. All subsequent tool calls from the MCP server will fail with unauthorized.

To rotate: delete the old key, mint a new one, update BETTERKEY_API_KEY in your MCP host config, restart the host.

Known upstream quirks the agent sees

The get_vehicle_capabilities tool returns a knownQuirks list so agents don't over-report:

  • isLockedWebhookUnreliable. The vehicle's upstream lock-state webhook is defective at the provider level; any lock state reported here is last-known, not live.

  • statusEndpointReturns501. There is no engine-run-state (on/off) tool for your vehicle.

If a tool call returns 401 unauthorized, the API key was revoked or regenerated. If it returns 403 with type: "insufficient_scope" and requiredScope: "vehicle.command", the key does not have the scope the called route requires; mint a new key with that scope and retry.

Security notes

  • The API key lives in your MCP host's env; it is never written to tool output or error messages.

  • Zod validates every tool argument before it reaches the HTTP client.

  • All path segments interpolated into URLs go through encodeURIComponent.

  • Timeouts default to 20s with Retry-After honored on 429.

  • fetch is called with redirect: "manual"; redirects fail closed.

Development

git clone https://github.com/CMLabsLLC/betterkey-mcp.git
cd betterkey-mcp
npm install
npm run dev        # run with tsx (no build step)
npm run typecheck  # strict typecheck without emit
npm test           # Node's built-in test runner
npm run build      # emit dist/

Point at a local backend by setting BETTERKEY_API_BASE=http://localhost:8080 and running make simulator-backend in the main BetterKey repo.

License

MIT

Available Tools

6 tools
get_vehicle_capabilitiesGet vehicle capabilitiesA

Describe what BetterKey can currently report for one vehicle: identity (make/model/color), the per-signal freshCapabilities map (true when a fresh reading is available right now), and a knownQuirks list of upstream Smartcar behaviors the agent should respect when reasoning about results.

NameRequiredDescriptionDefault
vehicle_idYesThe vehicle id from list_vehicles.

TDQS

A3.5/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden. It does useful work by defining field semantics (true = a fresh reading is available now; quirks are upstream Smartcar behaviors to respect), which implies a read-only probe. However, it says nothing about whether freshCapabilities triggers a live query, latency/caching, or permission requirements.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single front-loaded sentence that lists the three return components in a natural reading order with no filler. It is dense with parentheticals but every clause carries information; slight tightening of the nested asides would earn a 5.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description must characterize the return value, and it does: identity fields, a per-signal boolean map, and a quirks list. The shape of knownQuirks entries and how the agent should act on a false capability value remain underspecified, but the essential contract is conveyed.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Only one parameter exists and schema description coverage is 100% ('The vehicle id from list_vehicles'), so the schema already does the work. The description adds no further meaning about vehicle_id, making the baseline 3 appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description gives a specific verb ('Describe') and resource ('what BetterKey can currently report for one vehicle'), then enumerates the three returned components: identity, the freshCapabilities map, and knownQuirks. This makes it clearly a capability-probe rather than a data-fetch tool, implicitly separating it from get_vehicle_telemetry and get_vehicle_location, though no sibling is named.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied rather than stated: 'freshCapabilities... true when a fresh reading is available right now' and 'knownQuirks... the agent should respect when reasoning about results' hint that this should precede telemetry reasoning. There is no explicit when-to-use, when-not-to-use, or named alternative such as get_vehicle_telemetry.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_vehicle_locationGet vehicle locationA
Read-only

Fetch the vehicle's current reported location (latitude, longitude, and the OEM timestamp when known). This is sensitive data — the agent host should treat the result accordingly and should not persist coordinates beyond what the user asked for. Returns 503 with a Retry-After hint when the automaker's location pipe is in-flight or temporarily unavailable; retry only when the user asks.

NameRequiredDescriptionDefault
vehicle_idYesThe vehicle id from list_vehicles.

TDQS

A3.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, destructiveHint=false and openWorldHint=true, yet the description still adds meaningful context: the data is sensitive, should not be persisted beyond the user's request, and failures surface as 503 with a Retry-After hint. That error/retry disclosure goes beyond anything structured. It stops short of stating expected staleness or precision of the reported coordinates.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences, each carrying distinct information: payload, privacy obligation, error/retry behavior. Purpose is front-loaded. The privacy sentence is slightly advisory in tone but is not filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description appropriately names the return fields, and it covers the notable failure mode (503 + Retry-After). For a read-only single-parameter tool this is nearly complete; only the relative positioning against the telemetry sibling is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and the single parameter is documented as coming from list_vehicles, so the schema already does the work. The description adds no further meaning about the parameter, which is the expected baseline for a fully documented one-param schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource and enumerates the returned fields (latitude, longitude, OEM timestamp when known), so the agent knows exactly what data comes back. It does not, however, distinguish itself from the sibling get_vehicle_telemetry, leaving a telemetry-vs-location choice to inference.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit guidance on error handling — 'retry only when the user asks' after a 503 — which is real when-to-use guidance. But it offers no guidance on when to choose this tool over get_vehicle_telemetry, nor any preconditions beyond the vehicle_id requirement.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_vehicle_telemetryGet vehicle telemetryA

Fetch the latest telemetry snapshot (windows, odometer, fuel, battery) for one vehicle. Each returned signal carries oemUpdatedAt from the automaker and an isStale flag (true when the reading is older than 15 minutes). Pass refresh=true to bypass the server's 15-minute cache; most calls should leave it false.

NameRequiredDescriptionDefault
refreshNoIf true, bypass the server-side 15 min signal cache. Default false.
vehicle_idYesThe vehicle id from list_vehicles.

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations present, the description carries the full disclosure burden and does well: it reveals a 15-minute server-side cache, the 15-minute staleness threshold behind isStale, and the automaker-supplied oemUpdatedAt origin. It omits auth or rate-limit behavior, which keeps it short of a 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences, zero filler, with the core action and return content front-loaded before the cache/refresh caveat. Every sentence contributes new information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, and the description compensates by explaining what the returned signals carry (oemUpdatedAt, isStale) and what the cache means for freshness. An agent can call this correctly and interpret the response from the description alone.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3, but the description goes beyond the schema by advising that most calls should leave refresh false and tying refresh to the cache it bypasses. It adds genuine decision guidance rather than restating the schema text.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names a specific verb and resource (fetch the latest telemetry snapshot for one vehicle) and enumerates the signal classes it returns (windows, odometer, fuel, battery). That content list cleanly separates it from siblings such as get_vehicle_location and get_vehicle_capabilities without the agent needing to open any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear, prescriptive guidance on the refresh parameter ('most calls should leave it false'), but that is parameter usage rather than tool selection. It never states when to prefer this tool over get_vehicle_location or get_vehicle_capabilities, leaving the agent to infer the choice from the signal list.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_vehiclesList vehiclesA

List the user's Smartcar-connected vehicles in BetterKey. Returns id, display name, make, model, and exterior color. Use the id as the vehicle_id argument to other tools.

NameRequiredDescriptionDefault

No parameters

TDQS

A4.2/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden; it does disclose the read-only nature implicitly via 'List' and enumerates the returned fields. It omits permission/auth requirements and the behavior when the account has no connected vehicles (empty list vs error), which matters for a tool with zero annotation coverage.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short sentences, front-loaded with the resource and the return payload, then the follow-up instruction. No filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-parameter read tool with no output schema, the description supplies the return field summary that the schema cannot, plus the chaining hint. Only the empty-result/auth edge cases are unaddressed, which is a minor gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes no parameters, so the baseline is 4. The description adds useful cross-tool context by explaining the semantic value of the returned id as vehicle_id for downstream tools.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('List the user's Smartcar-connected vehicles') plus the exact fields returned. This clearly separates it from siblings like get_vehicle_telemetry, get_vehicle_capabilities, and the lock/unlock tools, which operate on a single vehicle.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly tells the agent to use the returned id as the vehicle_id argument to other tools, which establishes this as the entry point for the vehicle tool family. It stops short of naming which sibling to call next or stating when not to call it, but the chaining guidance is clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

lock_vehicleLock vehicleA
Destructive

Lock the vehicle. This physically actuates the car's door locks. The agent MUST obtain explicit human confirmation before invoking this tool. The response includes a confirmation field: 'confirmed' means the automaker acknowledged the command; 'unconfirmed' means BetterKey accepted it but the automaker's acknowledgement is unavailable (the lock may or may not have actuated) — report that honestly rather than assuming success.

NameRequiredDescriptionDefault
vehicle_idYesThe vehicle id from list_vehicles.

TDQS

A4.1/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the annotations: it explains that this is a physical actuation, imposes a human-confirmation gate, and — critically — decodes the response 'confirmed' vs 'unconfirmed' semantics, telling the agent to report uncertainty honestly rather than assume success. That response ambiguity is exactly the kind of context annotations cannot convey, and it is consistent with destructiveHint=true.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences, each front-loaded with its purpose: what it does, the safety gate, then the response interpretation. Zero filler and the confirmation requirement appears before the calling detail.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a one-parameter, non-idempotent mutation with no output schema, the description covers effect, precondition, and result ambiguity, which is nearly everything an agent needs. Missing only edge cases such as what an error or already-locked vehicle looks like.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Single parameter with 100% schema description coverage ('The vehicle id from list_vehicles'), so the schema already carries the semantics. The description adds nothing about the parameter, which is the expected baseline here.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (lock) and resource (the vehicle) plus the physical effect (door locks actuate), so the agent knows exactly what happens. It never names the obvious inverse sibling unlock_vehicle, but the verb/resource pairing is unambiguous enough on its own.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives a hard precondition — explicit human confirmation is required before invoking — which is the single most important usage rule for this tool. It does not contrast with unlock_vehicle or discuss when locking is inappropriate (e.g., vehicle in motion), so it stops short of full when/when-not guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

unlock_vehicleUnlock vehicleA
Destructive

Unlock the vehicle. This physically actuates the car's door locks and will leave the car unsecured until it is locked again. The agent MUST obtain explicit human confirmation before invoking this tool and should surface a clear reason to the user. The response includes a confirmation field: 'confirmed' means the automaker acknowledged the command; 'unconfirmed' means BetterKey accepted it but the automaker's acknowledgement is unavailable — report that honestly rather than assuming success.

NameRequiredDescriptionDefault
vehicle_idYesThe vehicle id from list_vehicles.

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already flag destructiveHint=true and idempotentHint=false, and the description adds substantial context beyond them: the car stays unsecured until locked, human confirmation is required, and the 'confirmed' vs 'unconfirmed' response semantics are spelled out so the agent does not overstate success.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the action and its physical effect, then the safety requirement, then the response caveat — each sentence carries unique operational value with no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a single-parameter destructive action with no output schema, the description supplies everything an agent needs: the physical consequence, the confirmation gate, and how to interpret the returned confirmation field.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Only one parameter, and its schema description ('The vehicle id from list_vehicles') already covers it at 100% coverage. The description adds nothing about the parameter, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Unlock the vehicle') and immediately explains the physical consequence, which distinguishes it from the sibling lock_vehicle and from read-only tools like get_vehicle_location.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives an explicit precondition ('MUST obtain explicit human confirmation before invoking') and instructs surfacing a reason to the user, which is strong when-to-use guidance. It stops short of naming lock_vehicle as the counterpart action.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 6 tool updatesv0.1.4
    • First observedget_vehicle_capabilities
    • First observedget_vehicle_location
    • First observedget_vehicle_telemetry
    • First observedlist_vehicles
    • First observedlock_vehicle
    • First observedunlock_vehicle

TDQS

A4.1/5.0

Scored across 6 tools

Disambiguation4/5

Each tool maps to a distinct resource plus action, and lock vs unlock vs list are unmistakable. The only candidate for confusion is get_vehicle_telemetry vs get_vehicle_capabilities, both returning per-vehicle diagnostic data, though the descriptions do clarify that one returns readings and the other returns what can be reported.

Naming Consistency5/5

All six tools follow a strict verb_noun pattern (list_vehicles, get_vehicle_*, lock_vehicle, unlock_vehicle) with the domain noun consistently suffixed. No mixing of conventions or vague verbs.

Tool Count5/5

Six tools is tightly scoped to the server's purpose: enumerate vehicles, read state, read capabilities, and two lock actuation commands. Every tool earns its place and none is redundant.

Completeness4/5

The surface covers discovery, telemetry, capabilities, location, and the lock/unlock command pair, which is solid coverage for a Smartcar read/control wrapper. Gaps remain for other common actuations (charging, climate, engine start) and there is no bulk/multi-vehicle read, but agents can work around these.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables AI assistants to access vehicle data from the DIMO Network, including querying telemetry, executing vehicle commands (lock/unlock, charging), decoding VINs, minting vehicle NFTs, and creating verifiable credentials.
    2
    MIT
  • F
    license
    A
    quality
    D
    maintenance
    Exposes a connected-vehicle OBD-II/telematics platform to AI agents, enabling vehicle health scoring, live data queries, DTC decoding, maintenance prediction, and gated remote commands via a pluggable data layer.
    9
    -