Skip to main content
Glama
imsnawaz

connected-vehicle-health

by imsnawaz
README.md
# 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

A4/5.0

Scored across 9 tools

Disambiguation5/5

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.

Naming Consistency5/5

All tool names follow a consistent verb_noun pattern in snake_case, e.g., list_vehicles, get_dtcs, send_command. No mixing of conventions.

Tool Count5/5

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.

Completeness5/5

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.

Maintenance

ActivitySlowing
ResponsivenessNo issues