panda-mcp

panda-mcp

Turns a comma.ai Panda into a conversational CAN reverse-engineering rig, allowing users to record, diff, find signals, and send frames through natural language with Claude.

Category
Visit Server

README

<div align="center">

๐Ÿผ panda-mcp

Reverse-engineer your car's CAN bus by talking to Claude.

An MCP server that turns a comma.ai Panda into a conversational CAN reverse-engineering rig โ€” record โ†’ diff โ†’ find the signal โ†’ confirm โ†’ send it back โ€” without writing a line of glue code.

Python MCP Tools Tests No hardware required License

</div>


Why this exists

Finding the one CAN frame that controls your blinker โ€” or your steering angle, or your door locks โ€” is a slow, fiddly loop: log traffic, do the thing, log again, diff bytes by hand, guess the CRC, replay it, repeat. Every step lives in a different script.

panda-mcp collapses that loop into a conversation. You tell Claude "record the bus, I'll flip the blinker, now find what changed" and it drives the Panda, runs comma.ai's own diff heuristics, cracks the CRC, and replays the candidate frame โ€” all through 26 typed MCP tools.

And because it ships with a full mock CAN bus, you can learn the entire workflow on your laptop on the train home, with no Panda and no car.

You:    Connect in mock mode, record a baseline, then record again โ€” I'll toggle the blinker.
Claude: [device_connect โ†’ capture_start โ†’ capture_stop ร—2]
You:    Which bits only showed up while blinking?
Claude: [analyze_diff_new_bits] โ†’ 0xE1, byte 0 bit 0 flipped 0โ†’1. That's your blinker.
You:    Prove it. Send it back.
Claude: [device_set_safety_mode('alloutput') โ†’ send_frame 0xE1 ...] โ†’ sent 20ร—. ๐Ÿš—๐Ÿ’ก

โœจ Features

  • ๐ŸŽ™๏ธ Background capture โ€” non-blocking recording with bus / arbitration-ID / duration / frame-count filters
  • ๐Ÿ” Two diff engines, straight from comma.ai โ€” can_bit_transition (clean 0โ†’1/1โ†’0 flips across a split) and can_unique (bits that appear only against a baseline)
  • ๐ŸŽฏ Signal hunting โ€” pin a known number (speed, RPM, steering angle) to an exact ID + byte offset + endianness
  • ๐Ÿ“ธ Snapshots โ€” freeze the bus state before/after an action and XOR-diff it
  • ๐Ÿ“ค Transmit & fuzz โ€” single frame, bulk, single-byte sweep, or full timed replay of a recording
  • ๐Ÿงฎ CRC toolkit โ€” a catalogue of real automotive CRCs (J1850, AUTOSAR, CCITTโ€ฆ), brute-force identification with per-message magic-init sweep, and automatic CRC-field detection across a whole capture
  • ๐Ÿงช Mock mode โ€” a deterministic synthetic bus that exercises every tool, so dev & tests need zero hardware
  • ๐Ÿ”’ Safe by default โ€” listen-only until you explicitly unlock transmission
  • ๐Ÿ’พ Interop โ€” export to candump .log for Cabana / SavvyCAN / can-utils

๐Ÿ“‘ Table of contents

๐Ÿš€ Quickstart

git clone https://github.com/<you>/panda-mcp.git
cd panda-mcp

py -m venv .venv
.venv/Scripts/python -m pip install -e .            # mock mode only
.venv/Scripts/python -m pip install -e ".[panda]"   # + real hardware (pandacan)

Register the server with Claude Code by pointing it at the bundled claude.json:

{
  "mcpServers": {
    "panda": {
      "command": ".venv/Scripts/python.exe",
      "args": ["-m", "panda_mcp.server"],
      "env": { "PYTHONPATH": "src" }
    }
  }
}

Then just ask Claude to device_connect(mock=true) and start exploring.

๐Ÿงช Mock mode

No Panda? No car? No problem. device_connect(mock=true) spins up a deterministic synthetic CAN stream designed to make every analysis tool light up:

Arb ID Rate Payload Demonstrates
0x1A0 20 Hz rolling counter nibble + J1850 CRC8 over bytes 0โ€“6 crc_detect_field, crc_brute_force
0x2B0 10 Hz static DEADBEEFโ€ฆ baseline noise for diffs
0x3C0 50 Hz int16 "steering angle" sweeping via sin(t) analyze_find_value
0x0E1 1 Hz one toggle bit driven by a virtual "blinker" analyze_diff_transition

Everything you learn in mock mode maps 1:1 onto real hardware โ€” only the mock=true flag changes.

๐Ÿ›  How it works

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   MCP tools    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚    Claude    โ”‚ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–บ โ”‚             panda_mcp.server            โ”‚
โ”‚  (you, chat) โ”‚ โ—„โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”‚            FastMCP ยท 26 tools           โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    results     โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                                     โ”‚
        โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
        โ–ผ                        โ–ผ                    โ–ผ                    โ–ผ
 โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”          โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”     โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”     โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
 โ”‚  device.py โ”‚          โ”‚  session.py  โ”‚     โ”‚ analysis.py  โ”‚     โ”‚   crc.py   โ”‚
 โ”‚ Panda  +   โ”‚          โ”‚ bg-threaded  โ”‚     โ”‚ bit-state    โ”‚     โ”‚ automotive โ”‚
 โ”‚ MockPanda  โ”‚          โ”‚ capture storeโ”‚     โ”‚ diff engines โ”‚     โ”‚ CRC engine โ”‚
 โ””โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”˜          โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜     โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜     โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
       โ”‚ USB
       โ–ผ
 โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
 โ”‚ Panda Red  โ”‚  STM32H725 ยท CAN/CAN-FD
 โ”‚  ๐Ÿš— car    โ”‚
 โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
Module Responsibility
server.py FastMCP entry point โ€” all 26 tools, argument parsing, safety gating
device.py Panda abstraction + MockPanda synthetic stream + safety-mode constants
session.py Background-threaded capture store and snapshots (all in-memory)
analysis.py Bit-state tracking, the two diff engines, find_value, per-ID stats
crc.py CRC catalogue, brute-force identification, CRC-field detection
model.py The CanFrame dataclass

๐Ÿ“– Tool reference

<table> <tr><th>Group</th><th>Tool</th><th>What it does</th></tr>

<tr><td rowspan="6"><b>Device</b></td> <td><code>device_connect</code></td><td>Connect to a Panda (or <code>mock=true</code>)</td></tr> <tr><td><code>device_status</code></td><td>Connection, firmware, safety mode, bus errors</td></tr> <tr><td><code>device_set_safety_mode</code></td><td><code>silent</code> (listen-only) / <code>alloutput</code> (unlock TX)</td></tr> <tr><td><code>device_set_can_speed</code></td><td>Set a bus bitrate in kbps</td></tr> <tr><td><code>device_flash</code></td><td>Flash stock or custom firmware</td></tr> <tr><td><code>device_recover</code></td><td>DFU recovery for a bricked device</td></tr>

<tr><td rowspan="5"><b>Capture</b></td> <td><code>capture_start</code></td><td>Begin recording (bus/ID/duration/count filters)</td></tr> <tr><td><code>capture_stop</code></td><td>Stop and summarize</td></tr> <tr><td><code>capture_list</code></td><td>List all captures</td></tr> <tr><td><code>capture_get</code></td><td>Page through raw frames</td></tr> <tr><td><code>capture_delete</code></td><td>Discard a capture</td></tr>

<tr><td rowspan="4"><b>Analyze</b></td> <td><code>analyze_stats</code></td><td>Per-ID count, period, length, dynamic bytes</td></tr> <tr><td><code>analyze_diff_transition</code></td><td>Clean bit flips before/after a split time</td></tr> <tr><td><code>analyze_diff_new_bits</code></td><td>Bits unique to a capture vs. baselines</td></tr> <tr><td><code>analyze_find_value</code></td><td>Locate a number โ†’ ID + offset + endianness</td></tr>

<tr><td rowspan="2"><b>Snapshot</b></td> <td><code>snapshot_take</code></td><td>Freeze latest payload per (bus, ID)</td></tr> <tr><td><code>snapshot_diff</code></td><td>XOR-diff two snapshots</td></tr>

<tr><td rowspan="4"><b>Send</b></td> <td><code>send_frame</code></td><td>Transmit one frame (optionally repeated)</td></tr> <tr><td><code>send_bulk</code></td><td>Transmit many frames at once</td></tr> <tr><td><code>send_fuzz</code></td><td>Sweep one byte across a range</td></tr> <tr><td><code>send_replay</code></td><td>Replay a capture with original timing</td></tr>

<tr><td rowspan="4"><b>CRC</b></td> <td><code>crc_compute</code></td><td>Compute a catalogued CRC over hex data</td></tr> <tr><td><code>crc_list</code></td><td>List CRC algorithms + parameters</td></tr> <tr><td><code>crc_brute_force</code></td><td>Identify the algorithm (with init sweep)</td></tr> <tr><td><code>crc_detect_field</code></td><td>Find the CRC byte + algo across a capture</td></tr>

<tr><td><b>Export</b></td> <td><code>export_candump</code></td><td>Write a candump <code>.log</code> (Cabana/SavvyCAN)</td></tr> </table>

๐Ÿงญ Workflows

Hunt down a control frame (the blinker)

device_connect(mock=true)

capture_start()                  โ†’ cap-aaaa          # baseline: do nothing
capture_stop(cap-aaaa)

capture_start()                  โ†’ cap-bbbb          # now toggle the blinker
capture_stop(cap-bbbb)

analyze_diff_new_bits(cap-bbbb, [cap-aaaa])          # bits unique to "blinking"
# โ€ฆor, if you toggled mid-capture:
analyze_diff_transition(cap-bbbb, split_ts=5.0)

device_set_safety_mode('alloutput')
send_frame(arb_id='0xE1', data='01000000000000', bus=0, count=20, interval_ms=50)

Pin a numeric signal (speed / RPM / steering)

analyze_find_value(cap-xxxx, value=2000, bit_length=16)
# โ†’ 0x3C0, byte_offset 0, little-endian, 14 matches

Crack a CRC

crc_detect_field(cap-xxxx, arb_id='0x1A0')
# โ†’ crc_index 7, confirmed: crc8_sae_j1850 (init 0xFF) across 30 frames โœ…

crc_brute_force(frame='10123456780000CC')            # single-frame identification
crc_compute(data='10123456780000', algorithm='crc8_sae_j1850')

โšก Sending frames vs. flashing firmware

You do not need custom firmware to send frames. Transmission is unlocked in software via the safety mode:

device_set_safety_mode('alloutput')

device_flash / device_recover exist only for firmware updates, custom on-device safety logic, or un-bricking:

  • device_flash() โ€” build & flash the stock firmware (the Panda's own flash())
  • device_flash('/path/fw.bin') โ€” flash a custom binary
  • device_recover() โ€” DFU recovery for an unresponsive device

The Panda Red is an STM32H725; flashing runs over USB DFU (VID 0x0483, PID 0xdf11). The device reboots afterward โ€” call device_connect again.

๐Ÿ”’ Safety

[!WARNING] Injecting frames onto a moving vehicle's powertrain bus can disable brakes, steering, or throttle. People can get hurt.

  • The server boots listen-only (silent). Transmission requires an explicit device_set_safety_mode('alloutput') โ€” there is no way to send by accident.
  • Only unlock output on a bench harness or a vehicle you own and have immobilized.
  • This project is for education, research, and tinkering on hardware you control. You are responsible for how you use it.

๐Ÿงฐ Development

.venv/Scripts/python -m pytest -q        # 7 hardware-free end-to-end tests

The whole test suite runs against MockPanda โ€” capture, both diff engines, find_value, CRC detection, the safety gate, and replay โ€” so CI never needs a device.

src/panda_mcp/
  server.py     FastMCP entry point ยท all 26 tools
  device.py     Panda abstraction + MockPanda synthetic stream
  session.py    background-threaded capture store + snapshots
  analysis.py   bit-state diffing + find_value + per-ID stats
  crc.py        automotive CRC catalogue + brute force + field detection
  model.py      CanFrame
tests/
  test_smoke.py hardware-free end-to-end tests

๐Ÿ—บ Roadmap

  • [ ] DBC decoding via cantools โ€” decode/encode against a .dbc
  • [ ] Persistence โ€” auto-save captures to disk, reload .candump/CSV as sessions
  • [ ] CAN-FD โ€” widen bit arrays to 64-byte payloads
  • [ ] Multi-message CRC counters โ€” auto-derive counter + checksum pairs
  • [ ] SavvyCAN/Cabana import alongside the existing export

Contributions welcome โ€” open an issue or PR. If you add a tool, add a mock signal that exercises it so the test suite stays hardware-free.

๐Ÿ™ Credits & license

The two diff engines are faithful ports of comma.ai's own examples โ€” can_bit_transition.py and can_unique.py. Hardware access is via the pandacan library. Huge thanks to comma.ai for open-sourcing the Panda.

Released under the MIT License โ€” same as panda.

<div align="center"> <sub>Built for CAN tinkerers. Not affiliated with comma.ai.</sub> </div>

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured