Integrations
Ways to drive CanLab from something else, and ways to extend it.
REST API
Start it from the REST API toolbar toggle. It binds to
127.0.0.1:8765 and prints a per-session token on start. Every
request needs an X-API-Token header.
GET / # live web dashboard (HTML, open)
GET /frames # last N frames (?n=N)
GET /signals # decoded DBC signals
GET /status # connection state and frame count
GET /memory # AI memory entries
POST /mark # add an event mark: {"label":"brake","action":"toggle"}
# action is toggle (default), begin, end or point
POST /inject # inject a frame: needs the token AND ARM TX
# {"id":"0x200","data":"01 02 03 04 05 06 07 08"}
Loopback only. It is meant for scripting the tool from the same machine, not
for exposing a bus to a network. /mark is what a phone uses to
say "this is the brake" while someone else drives; the mark lands on the
INTELLIGENCE tab's list and the TIMELINE.
/inject needs both a valid token and ARM TX on. The token
alone will not transmit.
MCP server: Claude, ChatGPT and Codex
CanLab is a Model Context Protocol server. An assistant connected to it can
load a capture, list IDs, read byte statistics and raw frames, run every
detector, draft a DBC, define and remove signals, decode frames, annotate
the timeline and rank bytes against those annotations, list reassembled
multi-frame messages, find repeated blocks, calibrate against a reference
file and read the live watch's events: 29 tools in
canlab/core/mcp_tools.py. No MCP tool transmits.
Putting frames on a wire stays behind ARM TX in the window, where a person
is watching.
The same tools are served two ways.
| Where | How |
|---|---|
| Inside the window | The MCP toolbar toggle, or Settings → MCP, starts a Streamable HTTP server on 127.0.0.1:8766/mcp over the capture you have loaded or are recording right now. A signal the assistant adds appears in DBC BUILDER as one undoable step. |
| Headless | canlab-mcp serves stdio and loads captures on request; canlab-mcp --http serves the same over HTTP with no window. |
Settings → MCP writes the exact configuration for each client and copies it to the clipboard. In short:
# Claude Code, against the running window (or a headless --http server)
claude mcp add --transport http canlab http://127.0.0.1:8766/mcp
# Claude Desktop and Codex CLI launch stdio servers, so bridge to the window
canlab-mcp --attach http://127.0.0.1:8766/mcp
# Claude Desktop, headless, no window needed
{"command": "/path/to/.venv/bin/canlab-mcp"}
ChatGPT connects from OpenAI's servers, so it cannot reach your loopback
address. Publish the server over HTTPS first, with
cloudflared tunnel --url http://127.0.0.1:8766 or ngrok, tick
allow connections from other machines, and add
https://<tunnel-host>/mcp as a connector. The
search and fetch tools exist for ChatGPT's
connector contract; Developer mode exposes the rest.
The in-window server takes an optional bearer token, but ChatGPT's connectors cannot send one. While a tunnel is up, anyone who learns the URL can read the capture and edit the signal list. Nothing can transmit, but close the tunnel when you are done.
Capture kit
A desktop captures well when someone is sitting at it. A day of driving
needs a logger that starts at boot, writes to disk as it goes, and lets the
driver say "this is the brake" without a screen. canlab-cli
capture is that logger; see the command
line page. It serves the same REST API as the window, with
/mark and /frames but without /inject,
so a phone on the same network can add marks while the kit records.
Plugins
Drop a .py file into ~/.canlab/plugins/. It needs
three things:
PLUGIN_NAME = "My Plugin"
PLUGIN_VERSION = "1.0"
def register(app):
# called with the MainWindow instance when the plugin is activated
...
From app you reach the shared application state, the loaded
frames as a pandas DataFrame, the signal definitions, the menu bar, and
anything in canlab.core. Full API, the event list and two
worked examples are in
docs/PLUGINS.md.
Metadata is read statically, so listing plugins never executes anything. Code runs only after you approve it, and approval is trust-on-first-use keyed by the file's SHA-256: editing an approved plugin changes its hash and asks again, so approved code cannot be silently swapped. Only approve plugins you trust.
AI engine
Four providers: Anthropic, OpenAI, Groq and Ollama, the last running locally with no key and nothing leaving the machine. Configure in Settings → API KEYS; the model field is editable, so a model id newer than the built-in list can be typed in.
What is sent, when you click Analyze on an ID, is that message's statistics: byte roles, message type and period, the checksum guess, similar IDs, and a sample of frames. Not your whole capture, and nothing at all until you supply a key and ask.
The offline findings are included in the prompt deliberately, so the model reasons about measured facts rather than raw hex. Its answers are still suggestions; treat them the way you would treat the heuristics.
Hardware adapters
Settings → CAN ADAPTERS keeps a list of named adapters and the toolbar switches between them, so a bench with a PEAK on one port and a CANable on another is two clicks rather than two retypings. Each adapter is a backend, a channel, a bitrate, a CAN FD flag and whatever else that backend needs, such as an slcan stick's serial baud rate or a socketcand host.
Detect connected asks every python-can backend what it can
see, reads CAN network devices from sysfs, and recognises common USB sticks
by vendor and product id. Test opens the adapter and listens
for one second; it never transmits, and when opening fails it names the fix,
whether that is the ip link command, a missing pip package or
the dialout group.
| Backend | Notes |
|---|---|
socketcan | Linux. The kernel owns the bitrate, so bring the device up first. PEAK, Kvaser, candleLight and 8devices adapters all appear here. |
gvret | SavvyCAN's own hardware: Macchina M2 and A0, EVTV CANDue, ESP32RET. python-can ships no backend for it, so CanLab supplies one in core/gvret.py and registers it as an interface. Give it a serial port, or <ip>:23 for a board on WiFi. |
slcan | CANable with slcan firmware, USBtin, Lawicel. |
gs_usb | candleLight over libusb, where there is no kernel driver. |
pcan, kvaser, vector, ixxat | Vendor drivers, which come from the vendor. |
virtual, udp_multicast | No hardware at all, for trying the application. |
pip install canlab[adapters] adds pyserial and gs_usb. A
comma.ai Panda is supported separately through
core/panda_backend.py, presented as a python-can compatible bus
with the safety model selectable. The multi-bus configuration in
Settings → MULTI-BUS captures from more than one
interface at once, which is what you want when a vehicle has separate
powertrain and body buses.
Trimming a capture
Tools → Trim capture cuts the loaded capture down to a time window, a frame or percentage range, a set of IDs or ID ranges, or one bus, with a live count as you type. The result either replaces what is loaded or is written to a file. Every analysis runs over whatever is loaded, so trimming first makes the detectors faster and their output shorter.