MCP-CAN
Health Gecti
- License — License: MIT
- Description — Repository has a description
- Active repo — Last push 0 days ago
- Community trust — 13 GitHub stars
Code Gecti
- Code scan — Scanned 12 files during light audit, no dangerous patterns found
Permissions Gecti
- Permissions — No dangerous permissions requested
Bu listing icin henuz AI raporu yok.
Vehicle CAN Bus, OBD-II and J1939 Diagnostics for LLMs (Model Context Protocol)
🚗 MCP-CAN: Vehicle CAN Bus, OBD-II and J1939 Diagnostics for LLMs (Model Context Protocol)
🔌 Virtual CAN + MCP Server
MCP-CAN is a Model Context Protocol (MCP) server that exposes automotive CAN bus, OBD-II (SAE J1979), UDS, and SAE J1939 diagnostic data to LLMs and AI agents. It ships a built-in virtual CAN bus with an ECU simulator, decodes traffic via a DBC database (cantools), and serves MCP tools over SSE or streamable-HTTP. No CAN hardware, adapter, or vehicle is required by default; optional SocketCAN/vCAN on Linux.
Use it to let an LLM read live CAN frames, decode signals, run OBD-II PID and UDS diagnostic requests, inspect J1939 PGNs/SPNs and DM1 trouble codes, and drive fault-injection scenarios, all against a simulated vehicle.
Keywords: MCP server, Model Context Protocol, CAN bus, CANbus, OBD-II, OBD2, on-board diagnostics, SAE J1939, UDS, ECU simulator, vehicle diagnostics, automotive, DBC, python-can, cantools, SocketCAN, LLM tools, AI agents.
✨ Highlights
- MCP server for CAN/OBD/UDS-diagnostics/J1939 → LLM/SLM (tools + DBC metadata, SSE or streamable-HTTP).
- Virtual CAN backend (python-can) out of the box; optional SocketCAN/vCAN on Linux.
- DBC-driven encoding/decoding via
cantools. - ECU simulator that streams multiple messages, plus OBD-II, UDS-style, and SAE J1939 responders.
- SAE J1939 (heavy-duty, 29-bit extended IDs): ID decomposition (priority/PGN/source+destination address), a curated PGN/SPN catalog (EEC1, EEC2, ET1, CCVS1, LFE1, DD1), Request PGN (
0xEA00) round trips, and DM1 active-DTC (SPN/FMI) broadcasts. Runs alongside the 11-bit bus; toggle withMCP_CAN_J1939_ENABLED. - Correlated driving-dynamics signal generation, plus named fault-injection scenarios (
overheat,abs_fault,low_fuel) with matching DTCs. - Typer CLI:
mcp-can(simulate, server, demo, frames, decode, monitor, dbc-info, obd-request, diag-request, fault, j1939-decode, j1939-pgns, j1939-request, j1939-dtcs). - Structured tool output (typed Pydantic models), duration-capped tool calls,
/healthz, colorized logging. - Read-only live web dashboard (
/dashboard): signal values and recent frames, updated over SSE. - Dockerfile + docker compose for server + simulator.
- Unit tests, type hints, lint config (ruff, mypy); see
CONTRIBUTING.md.
📁 Repository Layout
src/mcp_can/cli.py– Typer commandsbus.py– python-can helpersdbc.py– DBC loading/decodingobd.py– OBD-II (SAE J1979) request/response helpersdiagnostics.py– UDS-style diagnostic service/response-code logicj1939.py– SAE J1939: 29-bit ID decomposition, PGN/SPN catalog, DM1 DTCs, Request PGNconfig.py– env settings (MCP_CAN_*) + logging setupmodels.py– internal bus-layer dataclass (Frame)simulator/runner.py– ECU simulator + OBD/diagnostic responderssimulator/j1939_runner.py– J1939 broadcasters (EEC1/ET1/CCVS1/…), Request PGN responder, DM1 emittersimulator/state.py– correlated driving-dynamics state (RPM/speed/throttle/etc.)simulator/faults.py– named fault-injection presets + activation protocolserver/fastmcp_server.py– MCP tools/resources + dashboard routesserver/schemas.py– Pydantic models for MCP tool structured outputserver/live_state.py– background bus listener backing the dashboardserver/templates/dashboard.html– the dashboard page itself
vehicle.dbc– sample CAN database (incl. a UDS-like diagnostic schema)simulate-ecus.py,can-mcp.py– standalone run-without-installing entrypointsdocker/compose.yml,Dockerfiletests/– unit testsCONTRIBUTING.md,CHANGELOG.md
✅ Prerequisites
- Python 3.10+
- (Optional) Docker / Docker Compose
- (Optional) Ollama if you want a local LLM backend
📦 Install (Python)
From repo root:
pip install -r requirements.txt
pip install -e .
🚀 Quickstart (Simulator + MCP Server)
Two terminals:
# Terminal A: start ECU simulator on virtual bus0
mcp-can simulate
# Terminal B: start MCP server (SSE on 6278)
mcp-can server --port 6278
Single-process (helps on Windows if virtual backend doesn't share across processes):
mcp-can demo --port 6278
Sample interactions:
mcp-can frames --seconds 2
mcp-can decode 0x100 "01 02 03 04 05 06 07 08" # pretty table by default, --json for scripting
mcp-can dbc-info # table of every message/signal in the DBC
mcp-can monitor ENGINE_SPEED --seconds 3
mcp-can obd-request --service 0x01 --pid 0x0D
mcp-can diag-request --service-id 0x22 --parameter-id 0x05 # READ_DATA_BY_ID
mcp-can j1939-pgns # J1939 PGN/SPN catalog
mcp-can j1939-request 0xF004 # ask ECUs to send EEC1 (engine speed)
mcp-can j1939-dtcs # read the latest DM1 active-DTC broadcast
📊 Live Dashboard
With mcp-can demo (or server) running, open http://localhost:6278/dashboard in a browser: live signal values grouped by ECU message, and a scrolling feed of recent frames, updating ~2x/second over Server-Sent Events. It's read-only (view only, no controls to send frames) and self-contained: no build step, no external assets, works offline. Like everything bus-related here, it only shows data when the simulator shares the same process as the server (mcp-can demo); pointed at a bare mcp-can server with no simulator, it just shows "waiting for CAN traffic."

🛠️ Available MCP Tools & Resources
| Name | Type | Description |
|---|---|---|
read_can_frames |
tool | Raw frames from the last duration_s seconds. Returns instantly (served from a continuously-running history buffer, not a fresh listen window). |
decode_can_frame |
tool | Decode one frame's bytes into named signals. |
filter_frames |
tool | Like read_can_frames, filtered by arbitration ID and/or signal. |
monitor_signal |
tool | Timestamped samples of one decoded signal, from the same history buffer. |
get_vehicle_snapshot |
tool | Last known value of every signal seen so far, one entry per signal (not per frame) with an age_s freshness indicator: a single-call overview instead of decoding a frame stream yourself. |
send_obd_request |
tool | Standard OBD-II (SAE J1979) request; decodes known PIDs (coolant temp, speed, fuel level, fuel type). |
send_diagnostic_request |
tool | UDS-style diagnostic request (vehicle.dbc's DIAGNOSTIC_REQUEST); collects every ECU's response. |
activate_fault_scenario |
tool | Activate (or clear) a named fault-injection preset (overheat, abs_fault, low_fuel) in the running simulator; see below. |
decode_j1939_frame |
tool | Decompose a 29-bit J1939 ID (priority / PGN / source + destination address) and decode known SPNs from the payload. |
list_j1939_pgns |
tool | The J1939 PGN/SPN catalog this server can decode and request (bit layout, scaling, units). |
request_j1939_pgn |
tool | Send a J1939 Request PGN (0xEA00) and return the decoded responses (needs a simulator on this process's bus). |
read_j1939_dtcs |
tool | Most recent J1939 DM1 broadcast: lamp status plus every active SPN/FMI. Served from the frame history buffer. |
dbc_info |
resource (file://vehicle.dbc) |
Full DBC dump: nodes, messages, signals. |
read_can_frames/filter_frames/monitor_signal/read_j1939_dtcs are served from a single continuously-running history buffer (server/live_state.py) rather than each opening its own bus listener: they return immediately and won't miss frames sent between calls. send_obd_request/send_diagnostic_request/request_j1939_pgn are request/response and still wait live for a reply. In both cases, duration_s/timeout_s is capped by MCP_CAN_MAX_DURATION_S (default 30s; the history buffer retains at least that much, or 60s, whichever is larger). All tools return typed, structured content (see server/schemas.py) rather than ad-hoc JSON.
🩺 About the diagnostic responder
vehicle.dbc defines a UDS-like diagnostic schema: DIAGNOSTIC_REQUEST (one shared request frame) and four DIAGNOSTIC_RESPONSE_<ECU> messages, one per ECU, but the request has no per-ECU target field. The simulator treats every request as functionally addressed to all four ECUs, so send_diagnostic_request/diag-request may return more than one response. Supported services: START_DIAGNOSTIC_SESSION (0x10) and RESET_ECU (0x11) are acknowledged OK; READ_DATA_BY_ID (0x22) returns a deterministic canned value derived from the parameter ID; ROUTINE_CONTROL/READ_MEMORY/WRITE_MEMORY and anything unrecognized return SERVICE_NOT_SUPPORTED; see diagnostics.py::handle_service.
⚠️ Fault injection
Three named scenarios (simulator/faults.py::PRESETS) let you force the simulator into a specific fault state instead of waiting on random signal generation:
overheat–ENGINE_TEMPpinned to its hottest reportable value,SYSTEM_STATUSset toFAULT_PRESENT, DTCP0217(Engine Overtemp Condition).abs_fault– all fourWHEEL_SPEED_*signals stuck at zero,SYSTEM_STATUSset toFAULT_PRESENT, DTCC0035(Left Front Wheel Speed Sensor Circuit).low_fuel–FUEL_LEVELpinned critically low; no DTC (a low-fuel light isn't a stored trouble code on a real vehicle either).
Activating a scenario sends a small control frame on the bus (like OBD/diagnostic requests, this is a round trip to whichever process is running the simulator, so it needs mcp-can demo/simulate already running) and overrides the named signals until cleared. Any DTCs the active scenario sets show up in send_obd_request/obd-request's Mode 03 (service=3) response. Use mcp-can fault list or the activate_fault_scenario tool's docstring to see the current preset descriptions; pass preset=None (CLI: clear) to deactivate.
🚛 SAE J1939 (heavy-duty)
Alongside the light-vehicle 11-bit bus, the simulator also speaks SAE J1939 — the protocol on trucks, buses and off-highway equipment. J1939 rides 29-bit extended CAN IDs whose arbitration field is itself structured data: a 3-bit priority, an 18-bit Parameter Group Number (PGN), and an 8-bit source address (plus, for peer-to-peer "PDU1" PGNs, a destination address). src/mcp_can/j1939.py is a self-contained implementation of that layer (not DBC-driven — vehicle.dbc models an 11-bit light-vehicle bus).
What's simulated (simulator/j1939_runner.py), driven by the same correlated driving-dynamics state as the 11-bit signals:
| PGN | Acronym | Contents |
|---|---|---|
0xF004 |
EEC1 | Engine speed (SPN 190), actual engine percent torque (SPN 513) |
0xF003 |
EEC2 | Accelerator pedal position (SPN 91), percent load (SPN 92) |
0xFEEE |
ET1 | Engine coolant temperature (SPN 110), fuel temperature (SPN 174) |
0xFEF1 |
CCVS1 | Wheel-based vehicle speed (SPN 84) |
0xFEF2 |
LFE1 | Engine fuel rate (SPN 183), throttle valve position (SPN 51) |
0xFEFC |
DD1 | Fuel level (SPN 96) |
0xFECA |
DM1 | Active diagnostic trouble codes (SPN + FMI), broadcast at 1 Hz |
- Request PGN (
0xEA00):request_j1939_pgn/mcp-can j1939-request <pgn>send a request; the simulator re-broadcasts the requested PGN once. - DM1 / DTCs:
read_j1939_dtcs/mcp-can j1939-dtcsread the latest DM1. The fault-injection presets map to J1939 DTCs too —overheat→ SPN 110 FMI 0,abs_fault→ SPN 84 FMI 5,low_fuel→ SPN 96 FMI 18 — and the malfunction-indicator lamp turns on while a preset is active. - J1939 signals also appear in
get_vehicle_snapshotand the dashboard, grouped underJ1939:<acronym>. - Set
MCP_CAN_J1939_ENABLED=falsefor an 11-bit-only bus.
🔍 MCP Inspector (GUI for your tools)
Use the official Inspector to explore and call your MCP tools without writing a host:
npx @modelcontextprotocol/inspector
When prompted, connect to your server:
- URL:
http://localhost:6278/sse
You can then list tools/resources and call one (e.g. monitor ENGINE_SPEED for 5 seconds) and view structured output live.
🤖 Using with Ollama (local LLM)
- Ensure Ollama is running:
ollama serveand pull a model:ollama pull llama3 - Run simulator + MCP server (see Quickstart).
- Point your MCP-capable host at
http://localhost:6278/sseand configure its model endpoint tohttp://localhost:11434with your model name (e.g.,llama3). - Prompt the host: "Monitor ENGINE_SPEED for 5 seconds", "List all DBC messages", or "Send a READ_DATA_BY_ID diagnostic request for parameter 5."
If you need a minimal host, pair @modelcontextprotocol/sdk with Ollama (see SDK docs) or use Inspector for manual tool calls.
Example host config (OpenAI-compatible endpoint to local Ollama):
{
"model": {
"type": "openai-compatible",
"baseUrl": "http://localhost:11434/v1",
"model": "llama3"
},
"mcpServers": {
"can-mcp-server": {
"serverUrl": "http://localhost:6278/sse"
}
}
}
⌨️ CLI Reference
mcp-can simulate– start ECU simulator usingvehicle.dbc.mcp-can server [--port 6278] [--transport sse|streamable-http|stdio]– run the MCP server.mcp-can demo [--port] [--transport]– simulator + server in one process.mcp-can frames --seconds 1.0– capture raw frames as JSON.mcp-can decode <id> <data> [--json]– decode a single frame (table by default;idhex/decimal,dataspace/comma-separated bytes).mcp-can snapshot --seconds 1.0 [--json]– latest value of every signal seen while listening.mcp-can dbc-info [message]– table of every message/signal in the DBC, or just one message's.mcp-can monitor <signal> --seconds 2.0 [--json]– watch one signal (live output by default).mcp-can obd-request --service <hex|int> [--pid <hex|int>]– OBD-II request; response includes a decoded value for known PIDs.mcp-can diag-request --service-id <hex|int> [--parameter-id] [--data-field]– UDS-style diagnostic request; prints every ECU's response.mcp-can fault <preset|clear|list>– activate/clear a fault-injection scenario in a running simulator, or list available presets.mcp-can j1939-decode <id> <data> [--json]– decompose a 29-bit J1939 ID and decode known SPNs.mcp-can j1939-pgns– list the J1939 PGNs/SPNs this project can decode.mcp-can j1939-request <pgn> [--timeout 2.0]– send a J1939 Request PGN (0xEA00) and print decoded responses.mcp-can j1939-dtcs [--seconds 3.0]– listen for a J1939 DM1 broadcast and print its active trouble codes.
server/demo/simulate all print colorized logs (via rich) instead of raw text.
⚙️ Configuration
Env vars (prefix MCP_CAN_):
CAN_INTERFACE(defaultvirtual)CAN_CHANNEL(defaultbus0)DBC_PATH(defaultvehicle.dbc)MCP_PORT(default6278)MCP_TRANSPORT(defaultsse;streamable-httprequires a newermcpSDK; the server logs a clear error and exits if the installed version doesn't support it, rather than crashing on an SDK traceback)MAX_DURATION_S(default30.0) – caps every tool'sduration_s/timeout_sJ1939_ENABLED(defaulttrue) – run the SAE J1939 side of the simulator alongside the 11-bit signalsLOG_LEVEL(defaultINFO)CORS_ALLOW_ORIGINS(default["*"], JSON array e.g.["https://your-host.example"]) – allowed browser origins for the SSE endpoint. Credentialed requests (allow_credentials) are only enabled once this is narrowed to specific origins; wildcard + credentials is a combination browsers reject outright, so it's never turned on for the default"*". Override before any real deployment.
You can set these in a .env file at repo root.
🐳 Docker
Build:
docker build -t mcp-can .
Run (combined server + simulator):
docker run -d --name mcp-can -p 6278:6278 -p 5000:5000 -p 8080:8080 mcp-can
Compose (from docker/):
docker compose up -d --build
The compose file currently runs
serverandsimulatoras separate containers; like running them as two separate local processes, they won't share the virtual CAN bus unless the host provides a real sharedvcan0interface. For a working combined setup today, use the single-container Dockerfile above (mcp-can demo).
🧪 Development & Testing
See CONTRIBUTING.md for the full guide. Quick version:
pip install -r requirements.txt
pip install -e .
pip install pytest ruff mypy
ruff check .
mypy src
pytest -q
🔧 Troubleshooting
- No frames? Ensure both simulator and server use the same interface/channel (
virtual/bus0by default), and, on Windows, that they're the same process (mcp-can demo) rather than two separate ones. - DBC missing? Set
MCP_CAN_DBC_PATHor placevehicle.dbcin repo root. - Docker networking: expose
6278so your MCP host can reach it. streamable-httptransport fails immediately? Your installedmcppackage predates its support; the log line tells you. Switch tosseorpip install -U mcp(staying below2.0.0).
📄 License
MIT (see LICENSE). Educational/prototyping use only; use certified hardware for real automotive work.
Yorumlar (0)
Yorum birakmak icin giris yap.
Yorum birakSonuc bulunamadi