connected-vehicle-health
# Connected Vehicle Health — MCP Server
An [MCP](https://modelcontextprotocol.io) server that exposes a connected-vehicle
OBD-II / telematics platform to AI agents. It maps raw OBD-II PIDs and CAN signals
into a rolled-up **vehicle health score** and provides tools for querying live data,
decoding diagnostic trouble codes (DTCs), forecasting maintenance, and issuing gated
remote commands.
The data layer is **pluggable** (`src/provider.ts`). Two backends ship:
- **`salesforce`** (default) — live data from a Salesforce org's standard `Asset`
object (the vehicle; VIN in `SerialNumber`) joined to the custom
`Vehicle_Telemetry__c` object (`VIN__c == Asset.SerialNumber`).
- **`simulator`** — an in-memory mixed fleet (ICE, diesel, EV) with deterministic
signals and injectable faults; zero external dependencies.
Select with `VEHICLE_DATA_SOURCE=salesforce|simulator`. The tool/resource layer is
identical for both.
> **Full reference:** see [`DOCUMENTATION.md`](./DOCUMENTATION.md) for architecture,
> the complete tool/resource/type schema, the Salesforce field mapping, the scoring
> model, and extension points.
## What it exposes
### Tools
| Tool | Type | Purpose |
| --- | --- | --- |
| `list_vehicles` | read | Enumerate the fleet with profile + last-seen |
| `get_vehicle_health` | read | Overall + per-domain health score (0–100) |
| `read_live_pids` | read | Snapshot of selected live PID / CAN values |
| `get_dtcs` | read | Active stored / pending / permanent codes |
| `get_parameter_history` | read | Reproducible time-series for one PID |
| `decode_dtc` | read | Explain a code: causes, symptoms, fixes |
| `predict_maintenance` | compute | Ranked component failure risks |
| `clear_dtcs` | **action** | Reset codes / MIL (requires `confirm=true`) |
| `send_command` | **action** | Remote lock/climate/immobilize (requires `confirm=true`) |
### Resources
| URI | Content |
| --- | --- |
| `vehicle://{vin}/profile` | Make, model, year, powertrain, odometer |
| `vehicle://{vin}/health` | Latest health snapshot |
| `vehicle://{vin}/trips` | Recent trips + behavior events |
| `fleet://summary` | Fleet-wide health roll-up |
| `dtc://catalog` | DTC knowledge base |
## Health model
Seven domains, each scored 0–100 and weighted into the overall score. EVs drop
`emissions` and `fuel`; the remaining weights are renormalized to 100%.
| Domain | Weight | Driven by |
| --- | --- | --- |
| Powertrain | 25% | Misfires, timing, load |
| Emissions | 15% | Lambda, catalyst temp, EGR |
| Fuel | 12% | Short/long fuel trims |
| Battery | 18% | 12V voltage/SoH, HV SoH, cell delta |
| Thermal | 12% | Coolant, oil, HV pack temp |
| Driveline | 10% | Trans temp, tire pressures |
| DTC | 8% | Active code count + severity |
Overall status: `good` (≥80), `attention` (≥60), `critical` (<60).
**Sparse sources score honestly.** A domain is only scored when its signals are
present; domains with no data are omitted and the weights are renormalized over the
domains that *were* scored. So a Salesforce vehicle that reports only coolant temp,
battery %, tire pressure, and DTC codes is scored on `thermal`, `battery`, `driveline`,
and `dtc` — `powertrain`/`emissions`/`fuel` are simply not fabricated.
## Salesforce integration
The `salesforce` backend reads the org directly with [`jsforce`](https://jsforce.github.io/):
| Canonical field | Salesforce source | Notes |
| --- | --- | --- |
| VIN | `Asset.SerialNumber` | Drives vehicle identity |
| Make / model / year | parsed from `Asset.Name` | e.g. `2019 Honda Accord` |
| Powertrain | inferred | EV if make is EV-only or `Engine_Temp_F__c` ≈ 0 |
| Odometer | `Vehicle_Telemetry__c.Odometer_Miles__c` | miles → km |
| Coolant temp | `Engine_Temp_F__c` | °F → °C (omitted for EVs) |
| Tire pressure | `Tire_Pressure_PSI__c` | PSI → kPa (applied to all four) |
| Battery | `Battery_Percent__c` | HV SoC for EVs; 12V proxy for ICE |
| DTCs | `DTC_Codes__c` | comma/space-separated; decoded via the catalog |
The fleet is driven by the VINs present in `Vehicle_Telemetry__c`, so only vehicles
that actually report telemetry appear — unrelated `Asset` records are ignored.
### Authentication (first match wins)
1. `SF_ACCESS_TOKEN` + `SF_INSTANCE_URL`
2. `SF_USERNAME` + `SF_PASSWORD` (+ `SF_SECURITY_TOKEN`, `SF_LOGIN_URL`)
3. **Salesforce CLI** — `sf org display --target-org $SF_TARGET_ORG` (default alias
`vehicleHealth`). Easiest for local dev; just be logged in via `sf org login web`.
See `.env.example`. An expired CLI session is refreshed automatically on the next query.
### Actions on the Salesforce backend
Per-capability flags gate the two action tools:
| Action | Salesforce | Behavior |
| --- | --- | --- |
| `clear_dtcs` | **enabled** (`supportsClearDtcs`) | Inserts a new `Vehicle_Telemetry__c` snapshot carrying the latest readings with `DTC_Codes__c` emptied and a current timestamp. This becomes the newest reading, so subsequent reads report no active codes — a scan-tool-style clear that never mutates history. Requires `confirm=true`. |
| `send_command` | **disabled** (`supportsRemoteCommands`) | This org has no telematics command channel, so remote commands return a clear message and are not dispatched. |
Both actions are fully functional under the `simulator` backend.
## Setup
Requires Node.js 18+.
```bash
cd connected-vehicle-mcp
npm install
npm run build # compile TypeScript to dist/
```
Run directly during development (no build step):
```bash
npm run dev
```
Inspect interactively with the MCP Inspector:
```bash
npm run inspect
```
## Register with an MCP client
The server speaks **stdio**. Add it to your client config. For Cursor
(`.cursor/mcp.json` or the workspace `.mcp.json`):
```json
{
"mcpServers": {
"connected-vehicle-health": {
"type": "stdio",
"command": "node",
"args": ["/Users/sarfaraz.nawaz/Dev/PruJap/connected-vehicle-mcp/dist/index.js"],
"env": {
"VEHICLE_DATA_SOURCE": "salesforce",
"SF_TARGET_ORG": "vehicleHealth"
}
}
}
}
```
For Claude Desktop, add the same block to `claude_desktop_config.json`. To run
disconnected from an org, set `"VEHICLE_DATA_SOURCE": "simulator"`.
## Try it
Once connected to the org, ask the agent things like:
- "List the fleet and show any vehicle with health under 80." (Camry is critical)
- "Why is the check-engine light on for the 2018 Toyota Camry?" (reads + decodes DTCs)
- "Show the coolant temperature history for the Accord." (`get_parameter_history`)
- "Predict upcoming maintenance for the Camry." (overheat + misfire + low tires)
- "Is the Model 3's battery degrading?" (surfaces `P0A80` — replace hybrid battery pack)
## Safety & security notes
This simulator is for development. Before pointing it at real vehicles:
- **Gate all actions.** `clear_dtcs` and `send_command` require `confirm=true` and are
annotated `destructiveHint`. Drive-affecting commands (`immobilize`/`mobilize`) should
additionally require a second human approval and are always logged.
- **Scope auth per VIN** with short-lived tokens; never grant fleet-wide actuation by default.
- **Rate-limit and audit** every action; the simulator keeps an in-memory command log as a stand-in.
- **Treat VIN, GPS, and driver identity as PII.** Do not log to stdout (reserved for the MCP stream).
## Project layout
```
src/
index.ts MCP server: tool + resource registration, stdio transport
provider.ts DataProvider interface + factory (salesforce | simulator)
salesforceProvider.ts Live org backend: Asset + Vehicle_Telemetry__c via jsforce
simulatorProvider.ts In-memory simulator backend
fleet.ts Deterministic signal simulator + fault injection
health.ts Domain scoring + predictive-maintenance rules
pids.ts OBD-II PID catalog (PID → unit → reader)
dtcCatalog.ts DTC knowledge base + classifier for decode_dtc
audit.ts In-memory action/command audit log
types.ts Shared domain types
```
TDQS
Scored across 9 tools
Each tool has a distinct purpose: vehicle listing, health scoring, DTC management (decode, get, clear), parameter history, live PIDs, maintenance prediction, and remote commands. No overlap.
All tool names follow a consistent verb_noun pattern in snake_case, e.g., list_vehicles, get_dtcs, send_command. No mixing of conventions.
Nine tools is well-scoped for a vehicle health domain covering diagnostics, health monitoring, historical data, live data, predictions, and commands. Not over- or under-tooled.
The tool surface covers the full lifecycle: vehicle discovery, health assessment, DTC handling (get, decode, clear), parameter history, live readings, predictive maintenance, and remote commands. No obvious gaps for the stated purpose.